mlxsw: Fix port range register leak
Subsystems (4)
Petr Machata
maintainercover 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
Petr Machata
maintainerPATCH 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.
--- 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
@@ -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
@@ -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
@@ -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
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 aflow_cls_offloadtemplate into a stack-local structmlxsw_sp_acl_rule_infopurely to compute rulei.values.elusage. Parsing can acquire port range registers viamlxsw_sp_flower_parse_ports_range(), but since this rulei never goes throughmlxsw_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 frommlxsw_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")Reported-by Wentao Liang <[email protected]>Reviewed-by Ido Schimmel <[email protected]>Signed-off-by Petr Machata <[email protected]>--- 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@@ -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@@ -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@@ -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,
Petr Machata
maintainerPATCH 2/2 selftests: mlxsw: Test port range occupancy on template create
In reply to Petr MachataAdd 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
@@ -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
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
Assisted-by LLMReviewed-by Ido Schimmel <[email protected]>Signed-off-by Petr Machata <[email protected]>--- .../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@@ -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
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 intmplt_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