Commit 6043819e authored by Moshe Shemesh's avatar Moshe Shemesh Committed by Jakub Kicinski
Browse files

net/mlx5: fs, fix UAF in flow counter release



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: b581f426 ("net/mlx5: fs, manage flow counters HWS action sharing by refcount")
Signed-off-by: default avatarMoshe Shemesh <moshe@nvidia.com>
Reviewed-by: default avatarYevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: default avatarMark Bloch <mbloch@nvidia.com>
Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/1758525094-816583-2-git-send-email-tariqt@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 0efdfbba
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
	}

+1 −0
Original line number Diff line number Diff line
@@ -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;
+22 −3
Original line number Diff line number Diff line
@@ -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);
}
+7 −1
Original line number Diff line number Diff line
@@ -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);
}
+2 −0
Original line number Diff line number Diff line
@@ -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);