]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net/mlx5: fs, fix UAF in flow counter release
authorMoshe Shemesh <moshe@nvidia.com>
Mon, 22 Sep 2025 07:11:32 +0000 (10:11 +0300)
committerJakub Kicinski <kuba@kernel.org>
Wed, 24 Sep 2025 00:17:30 +0000 (17:17 -0700)
Fix a kernel trace [1] caused by releasing an HWS action of a local flow
counter in mlx5_cmd_hws_delete_fte(), where the HWS action refcount and
mutex were not initialized and the counter struct could already be freed
when deleting the rule.

Fix it by adding the missing initializations and adding refcount for the
local flow counter struct.

[1] Kernel log:
 Call Trace:
  <TASK>
  dump_stack_lvl+0x34/0x48
  mlx5_fs_put_hws_action.part.0.cold+0x21/0x94 [mlx5_core]
  mlx5_fc_put_hws_action+0x96/0xad [mlx5_core]
  mlx5_fs_destroy_fs_actions+0x8b/0x152 [mlx5_core]
  mlx5_cmd_hws_delete_fte+0x5a/0xa0 [mlx5_core]
  del_hw_fte+0x1ce/0x260 [mlx5_core]
  mlx5_del_flow_rules+0x12d/0x240 [mlx5_core]
  ? ttwu_queue_wakelist+0xf4/0x110
  mlx5_ib_destroy_flow+0x103/0x1b0 [mlx5_ib]
  uverbs_free_flow+0x20/0x50 [ib_uverbs]
  destroy_hw_idr_uobject+0x1b/0x50 [ib_uverbs]
  uverbs_destroy_uobject+0x34/0x1a0 [ib_uverbs]
  uobj_destroy+0x3c/0x80 [ib_uverbs]
  ib_uverbs_run_method+0x23e/0x360 [ib_uverbs]
  ? uverbs_finalize_object+0x60/0x60 [ib_uverbs]
  ib_uverbs_cmd_verbs+0x14f/0x2c0 [ib_uverbs]
  ? do_tty_write+0x1a9/0x270
  ? file_tty_write.constprop.0+0x98/0xc0
  ? new_sync_write+0xfc/0x190
  ib_uverbs_ioctl+0xd7/0x160 [ib_uverbs]
  __x64_sys_ioctl+0x87/0xc0
  do_syscall_64+0x59/0x90

Fixes: b581f4266928 ("net/mlx5: fs, manage flow counters HWS action sharing by refcount")
Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/1758525094-816583-2-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/fs_hws_pools.c
include/linux/mlx5/fs.h

index db552c012b4f4ff70a3bce12d133187b6c2e908a..80245c38dbad39bf03efc0959ffacfa36fc4a88f 100644 (file)
@@ -663,7 +663,7 @@ static void del_sw_hw_rule(struct fs_node *node)
                        BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION) |
                        BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS);
                fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT;
-               mlx5_fc_local_destroy(rule->dest_attr.counter);
+               mlx5_fc_local_put(rule->dest_attr.counter);
                goto out;
        }
 
index 500826229b0beb5573085b94fe28ce31e053a5db..e6a95b310b55542252e0fef730e8eee6fd0950af 100644 (file)
@@ -343,6 +343,7 @@ struct mlx5_fc {
        enum mlx5_fc_type type;
        struct mlx5_fc_bulk *bulk;
        struct mlx5_fc_cache cache;
+       refcount_t fc_local_refcount;
        /* last{packets,bytes} are used for calculating deltas since last reading. */
        u64 lastpackets;
        u64 lastbytes;
index 492775d3d193a352e49265c7299db00e6f33d86b..83001eda38842a48c9447fb813183c03c8b8327f 100644 (file)
@@ -562,17 +562,36 @@ mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size)
        counter->id = counter_id;
        fc_bulk->base_id = counter_id - offset;
        fc_bulk->fs_bulk.bulk_len = bulk_size;
+       refcount_set(&fc_bulk->hws_data.hws_action_refcount, 0);
+       mutex_init(&fc_bulk->hws_data.lock);
        counter->bulk = fc_bulk;
+       refcount_set(&counter->fc_local_refcount, 1);
        return counter;
 }
 EXPORT_SYMBOL(mlx5_fc_local_create);
 
 void mlx5_fc_local_destroy(struct mlx5_fc *counter)
 {
-       if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
-               return;
-
        kfree(counter->bulk);
        kfree(counter);
 }
 EXPORT_SYMBOL(mlx5_fc_local_destroy);
+
+void mlx5_fc_local_get(struct mlx5_fc *counter)
+{
+       if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
+               return;
+
+       refcount_inc(&counter->fc_local_refcount);
+}
+
+void mlx5_fc_local_put(struct mlx5_fc *counter)
+{
+       if (!counter || counter->type != MLX5_FC_TYPE_LOCAL)
+               return;
+
+       if (!refcount_dec_and_test(&counter->fc_local_refcount))
+               return;
+
+       mlx5_fc_local_destroy(counter);
+}
index f1ecdba74e1f46828a681c5b1b326ef1f161d7b9..839d71bd42164f894c1c4e04931453814151f513 100644 (file)
@@ -407,15 +407,21 @@ struct mlx5hws_action *mlx5_fc_get_hws_action(struct mlx5hws_context *ctx,
 {
        struct mlx5_fs_hws_create_action_ctx create_ctx;
        struct mlx5_fc_bulk *fc_bulk = counter->bulk;
+       struct mlx5hws_action *hws_action;
 
        create_ctx.hws_ctx = ctx;
        create_ctx.id = fc_bulk->base_id;
        create_ctx.actions_type = MLX5HWS_ACTION_TYP_CTR;
 
-       return mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx);
+       mlx5_fc_local_get(counter);
+       hws_action = mlx5_fs_get_hws_action(&fc_bulk->hws_data, &create_ctx);
+       if (!hws_action)
+               mlx5_fc_local_put(counter);
+       return hws_action;
 }
 
 void mlx5_fc_put_hws_action(struct mlx5_fc *counter)
 {
        mlx5_fs_put_hws_action(&counter->bulk->hws_data);
+       mlx5_fc_local_put(counter);
 }
index 86055d55836d944deb86aadf8b6207bc9ef07ca3..6ac76a0c38277304a26d091f0ef6b41e49cde5f2 100644 (file)
@@ -308,6 +308,8 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
 void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
 struct mlx5_fc *mlx5_fc_local_create(u32 counter_id, u32 offset, u32 bulk_size);
 void mlx5_fc_local_destroy(struct mlx5_fc *counter);
+void mlx5_fc_local_get(struct mlx5_fc *counter);
+void mlx5_fc_local_put(struct mlx5_fc *counter);
 u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
 void mlx5_fc_query_cached(struct mlx5_fc *counter,
                          u64 *bytes, u64 *packets, u64 *lastuse);