Skip to contentSkip to conversation

mlxsw: Fix port range register leak

PATCH Applied Petr Machata 3 participants 6 messages Oct 6 – Oct 8

Subsystems (4)
lore
Share & tools
lore

Petr Machata

author maintainer
#0 lore raw

cover mlxsw: Fix port range register leak

When the mlxsw driver parses a port range template rule, it acquires the actual port range registers. The parsing is only done to determine the element usage, so the registers can be deallocated right away, but this is never done, and the registers are leaked. Plug this leak and add a selftest that would have caught it.

Petr Machata (2):
mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()
selftests: mlxsw: Test port range occupancy on template create

 .../net/ethernet/mellanox/mlxsw/spectrum.h    |  2 ++
 .../ethernet/mellanox/mlxsw/spectrum_acl.c    | 10 +++++--
 .../ethernet/mellanox/mlxsw/spectrum_flower.c |  9 +++++--
 .../drivers/net/mlxsw/port_range_occ.sh       | 26 +++++++++++++++++++
 4 files changed, 43 insertions(+), 4 deletions(-)
Signature · 1 line
2.55.0
author maintainer
#1 lore raw

PATCH 1/2 mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()

mlxsw_sp_flower_tmplt_create() parses a flow_cls_offload template into a stack-local struct mlxsw_sp_acl_rule_info purely to compute rulei.values.elusage. Parsing can acquire port range registers via mlxsw_sp_flower_parse_ports_range(), but since this rulei never goes through mlxsw_sp_acl_rulei_destroy(), those registers were never released, including through chain template deletion.

Factor out of mlxsw_sp_acl_rulei_destroy() the code to actually release the necessary resources and call from mlxsw_sp_flower_tmplt_create() to plug the leak.

The issue was found during a review of Wentao Liang's patch referenced below.

Fixes fe22f7410527 ("mlxsw: spectrum_flower: Add ability to match on port ranges")
---
 drivers/net/ethernet/mellanox/mlxsw/spectrum.h        |  2 ++
 drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c    | 10 ++++++++--
 drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c |  9 +++++++--
 3 files changed, 17 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum.h +2 -0
index b03ff9e044f9..10af08ce72ef 100644
@@ -989,6 +989,8 @@ void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
 struct mlxsw_sp_acl_rule_info *
 mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
 			  struct mlxsw_afa_block *afa_block);
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+			     const struct mlxsw_sp_acl_rule_info *rulei);
 void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
 				struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei);
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +8 -2
index cb232accb296..f7be4f3a1518 100644
@@ -340,8 +340,8 @@ mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
 	return ERR_PTR(err);
 }
 
-void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
-				struct mlxsw_sp_acl_rule_info *rulei)
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+			     const struct mlxsw_sp_acl_rule_info *rulei)
 {
 	if (rulei->action_created)
 		mlxsw_afa_block_destroy(rulei->act_block);
@@ -351,6 +351,12 @@ void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
 	if (rulei->dst_port_range_reg_valid)
 		mlxsw_sp_port_range_reg_put(mlxsw_sp,
 					    rulei->dst_port_range_reg_index);
+}
+
+void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
+				struct mlxsw_sp_acl_rule_info *rulei)
+{
+	mlxsw_sp_acl_rulei_free(mlxsw_sp, rulei);
 	kfree(rulei);
 }
 
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +7 -2
index 353fd9ca89a6..5e4632cb792d 100644
@@ -862,14 +862,19 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
 	memset(&rulei, 0, sizeof(rulei));
 	err = mlxsw_sp_flower_parse(mlxsw_sp, block, &rulei, f);
 	if (err)
-		return err;
+		goto out;
+
 	ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block,
 					   f->common.chain_index,
 					   MLXSW_SP_ACL_PROFILE_FLOWER,
 					   &rulei.values.elusage);
+	err = PTR_ERR_OR_ZERO(ruleset);
+
+out:
+	mlxsw_sp_acl_rulei_free(mlxsw_sp, &rulei);
 
 	/* keep the reference to the ruleset */
-	return PTR_ERR_OR_ZERO(ruleset);
+	return err;
 }
 
 void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
Signature · 1 line
2.55.0
Reviewed-by on v1 1/2
#2 lore raw

Re: [PATCH net 1/2] mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()

Quoted 11 lines · Petr Machata

mlxsw_sp_flower_tmplt_create() parses a flow_cls_offload template into a stack-local struct mlxsw_sp_acl_rule_info purely to compute rulei.values.elusage. Parsing can acquire port range registers via mlxsw_sp_flower_parse_ports_range(), but since this rulei never goes through mlxsw_sp_acl_rulei_destroy(), those registers were never released, including through chain template deletion.

Factor out of mlxsw_sp_acl_rulei_destroy() the code to actually release the necessary resources and call from mlxsw_sp_flower_tmplt_create() to plug the leak.

Since mlxsw_sp_acl_rulei_destroy() now just calls free + a kfree, it would also be reasonable to just convert to heap allocated structure instead of keeping it on the stack since you have to call a function either way.

No strong objection to this implementation though, and it leaves more of the other code unchanged. The stack use has already been accepted anyways.

Quoted 81 lines

The issue was found during a review of Wentao Liang's patch referenced below.

Fixes fe22f7410527 ("mlxsw: spectrum_flower: Add ability to match on port ranges")
---
 drivers/net/ethernet/mellanox/mlxsw/spectrum.h        |  2 ++
 drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c    | 10 ++++++++--
 drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c |  9 +++++++--
 3 files changed, 17 insertions(+), 4 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum.h +2 -0
index b03ff9e044f9..10af08ce72ef 100644
@@ -989,6 +989,8 @@ void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
 struct mlxsw_sp_acl_rule_info *
 mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
 			  struct mlxsw_afa_block *afa_block);
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+			     const struct mlxsw_sp_acl_rule_info *rulei);
 void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
 				struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei);
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +8 -2
index cb232accb296..f7be4f3a1518 100644
@@ -340,8 +340,8 @@ mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
 	return ERR_PTR(err);
 }
 
-void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
-				struct mlxsw_sp_acl_rule_info *rulei)
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+			     const struct mlxsw_sp_acl_rule_info *rulei)
 {
 	if (rulei->action_created)
 		mlxsw_afa_block_destroy(rulei->act_block);
@@ -351,6 +351,12 @@ void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
 	if (rulei->dst_port_range_reg_valid)
 		mlxsw_sp_port_range_reg_put(mlxsw_sp,
 					    rulei->dst_port_range_reg_index);
+}
+
+void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
+				struct mlxsw_sp_acl_rule_info *rulei)
+{
+	mlxsw_sp_acl_rulei_free(mlxsw_sp, rulei);
 	kfree(rulei);
 }
 
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +7 -2
index 353fd9ca89a6..5e4632cb792d 100644
@@ -862,14 +862,19 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
 	memset(&rulei, 0, sizeof(rulei));
 	err = mlxsw_sp_flower_parse(mlxsw_sp, block, &rulei, f);
 	if (err)
-		return err;
+		goto out;
+
 	ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block,
 					   f->common.chain_index,
 					   MLXSW_SP_ACL_PROFILE_FLOWER,
 					   &rulei.values.elusage);
+	err = PTR_ERR_OR_ZERO(ruleset);
+
+out:
+	mlxsw_sp_acl_rulei_free(mlxsw_sp, &rulei);
 
 	/* keep the reference to the ruleset */
-	return PTR_ERR_OR_ZERO(ruleset);
+	return err;
 }
 
 void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
author maintainer
#3 lore raw

PATCH 2/2 selftests: mlxsw: Test port range occupancy on template create

In reply to Petr Machata

Add a test that creates a tc chain template matching on both source and destination port ranges and verifies via devlink-resource occupancy that this does not leak port range registers, neither while the template exists nor after it is deleted.

---
 .../drivers/net/mlxsw/port_range_occ.sh       | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
tools/testing/selftests/drivers/net/mlxsw/port_range_occ.sh +26 -0
index b1f0781f6b25..c7eba3f15066 100755
@@ -9,6 +9,7 @@ lib_dir=$(dirname $0)/../../../net/forwarding
 
 ALL_TESTS="
 	port_range_occ_test
+	port_range_occ_tmplt_test
 "
 NUM_NETIFS=2
 source $lib_dir/lib.sh
@@ -101,6 +102,31 @@ port_range_occ_test()
 	log_test "port range occupancy"
 }
 
+port_range_occ_tmplt_test()
+{
+	local occ
+
+	RET=0
+	occ=$(port_range_occ_get)
+
+	# Addition of a chain template should not impact occupancy.
+	tc chain add dev "$swp1" ingress chain 1 protocol ip \
+		flower ip_proto udp src_port 501-600 dst_port 701-800
+	check_err $? "Could not add chain template"
+
+	(( occ == $(port_range_occ_get) ))
+	check_err $? "Got occupancy $(port_range_occ_get), expected $occ"
+
+	# And just for completeness sake, neither should deletion.
+	tc chain del dev "$swp1" ingress chain 1
+	check_err $? "Could not delete chain template"
+
+	(( occ == $(port_range_occ_get) ))
+	check_err $? "Got occupancy $(port_range_occ_get), expected $occ"
+
+	log_test "port range occupancy after template create/destroy"
+}
+
 trap cleanup EXIT
 
 setup_prepare
Signature · 1 line
2.55.0
Reviewed-by on v1 2/2
#4 lore raw

Re: [PATCH net 2/2] selftests: mlxsw: Test port range occupancy on template create

Quoted 5 lines · Petr Machata

Add a test that creates a tc chain template matching on both source and destination port ranges and verifies via devlink-resource occupancy that this does not leak port range registers, neither while the template exists nor after it is deleted.

Nice to see this covered by a selftest :D

Thanks,
Jake

Quoted 51 lines
---
 .../drivers/net/mlxsw/port_range_occ.sh       | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
tools/testing/selftests/drivers/net/mlxsw/port_range_occ.sh +26 -0
index b1f0781f6b25..c7eba3f15066 100755
@@ -9,6 +9,7 @@ lib_dir=$(dirname $0)/../../../net/forwarding
 
 ALL_TESTS="
 	port_range_occ_test
+	port_range_occ_tmplt_test
 "
 NUM_NETIFS=2
 source $lib_dir/lib.sh
@@ -101,6 +102,31 @@ port_range_occ_test()
 	log_test "port range occupancy"
 }
 
+port_range_occ_tmplt_test()
+{
+	local occ
+
+	RET=0
+	occ=$(port_range_occ_get)
+
+	# Addition of a chain template should not impact occupancy.
+	tc chain add dev "$swp1" ingress chain 1 protocol ip \
+		flower ip_proto udp src_port 501-600 dst_port 701-800
+	check_err $? "Could not add chain template"
+
+	(( occ == $(port_range_occ_get) ))
+	check_err $? "Got occupancy $(port_range_occ_get), expected $occ"
+
+	# And just for completeness sake, neither should deletion.
+	tc chain del dev "$swp1" ingress chain 1
+	check_err $? "Could not delete chain template"
+
+	(( occ == $(port_range_occ_get) ))
+	check_err $? "Got occupancy $(port_range_occ_get), expected $occ"
+
+	log_test "port range occupancy after template create/destroy"
+}
+
 trap cleanup EXIT
 
 setup_prepare
#5 lore raw
In reply to Petr Machata
This series was applied to netdev/net.git (main) by Jakub Kicinski <[email protected]>:

Hello:

This series was applied to netdev/net.git (main)
by Jakub Kicinski <[email protected]>:

Quoted 11 lines · On Tue, 6 Oct 2026 16:21:27 +0200 you wrote:

When the mlxsw driver parses a port range template rule, it acquires the actual port range registers. The parsing is only done to determine the element usage, so the registers can be deallocated right away, but this is never done, and the registers are leaked. Plug this leak and add a selftest that would have caught it.

Petr Machata (2):
mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()
selftests: mlxsw: Test port range occupancy on template create

[...]

Here is the summary with links:
- [net,1/2] mlxsw: spectrum_flower: Fix port range register leak in tmplt_create()

    https://git.kernel.org/netdev/net/c/7ea07afb230f
  - [net,2/2] selftests: mlxsw: Test port range occupancy on template create
    https://git.kernel.org/netdev/net/c/71198b59df56

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html