Skip to content

Commit 2398e49

Browse files
dtatuleagregkh
authored andcommitted
net/mlx5: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list
[ Upstream commit 894e036 ] mlx5_query_nic_vport_mac_list() sizes its firmware command buffer using the PF's log_max_current_uc/mc_list capabilities. When querying a VF vport with a larger configured max (via devlink), the firmware response can overflow this buffer: BUG: KASAN: slab-out-of-bounds in mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] Read of size 4 at addr ff1100013ffc8a12 by task kworker/u96:2/385 CPU: 12 UID: 0 PID: 385 Comm: kworker/u96:2 Not tainted 7.0.0-rc6+ #1 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009) Workqueue: mlx5_esw_wq esw_vport_change_handler [mlx5_core] Call Trace: <TASK> dump_stack_lvl+0x69/0xa0 print_report+0x176/0x4e4 kasan_report+0xc8/0x100 mlx5_query_nic_vport_mac_list+0x453/0x4c0 [mlx5_core] esw_update_vport_addr_list+0x2e3/0xda0 [mlx5_core] esw_vport_change_handle_locked+0xa1f/0x1060 [mlx5_core] esw_vport_change_handler+0x6a/0x90 [mlx5_core] process_one_work+0x87f/0x15e0 worker_thread+0x62b/0x1020 kthread+0x375/0x490 ret_from_fork+0x4dc/0x810 ret_from_fork_asm+0x11/0x20 </TASK> Fix by querying the vport's own HCA caps to size the buffer correctly. Refactor the function to allocate and return the MAC list internally, removing the caller's dependency on knowing the correct max. Fixes: e16aea2 ("net/mlx5: Introduce access functions to modify/query vport mac lists") Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com> Reviewed-by: Carolina Jubran <cjubran@nvidia.com> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/20260604135849.458060-1-tariqt@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 3b20ec8 commit 2398e49

3 files changed

Lines changed: 59 additions & 30 deletions

File tree

drivers/net/ethernet/mellanox/mlx5/core/eswitch.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -533,23 +533,16 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
533533
struct mlx5_vport *vport, int list_type)
534534
{
535535
bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
536-
u8 (*mac_list)[ETH_ALEN];
536+
u8 (*mac_list)[ETH_ALEN] = NULL;
537537
struct l2addr_node *node;
538538
struct vport_addr *addr;
539539
struct hlist_head *hash;
540540
struct hlist_node *tmp;
541-
int size;
541+
int size = 0;
542542
int err;
543543
int hi;
544544
int i;
545545

546-
size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
547-
MLX5_MAX_MC_PER_VPORT(esw->dev);
548-
549-
mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
550-
if (!mac_list)
551-
return;
552-
553546
hash = is_uc ? vport->uc_list : vport->mc_list;
554547

555548
for_each_l2hash_node(node, tmp, hash, hi) {
@@ -561,7 +554,7 @@ static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
561554
goto out;
562555

563556
err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,
564-
mac_list, &size);
557+
&mac_list, &size);
565558
if (err)
566559
goto out;
567560
esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",

drivers/net/ethernet/mellanox/mlx5/core/vport.c

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -324,35 +324,63 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu)
324324
}
325325
EXPORT_SYMBOL_GPL(mlx5_modify_nic_vport_mtu);
326326

327+
static int mlx5_vport_max_mac_list_size(struct mlx5_core_dev *dev, u16 vport,
328+
enum mlx5_list_type list_type)
329+
{
330+
void *query_ctx, *hca_caps;
331+
int ret = 0;
332+
333+
if (!vport && !mlx5_core_is_ecpf(dev))
334+
return list_type == MLX5_NVPRT_LIST_TYPE_UC ?
335+
1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
336+
1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
337+
338+
query_ctx = kzalloc(MLX5_ST_SZ_BYTES(query_hca_cap_out), GFP_KERNEL);
339+
if (!query_ctx)
340+
return -ENOMEM;
341+
342+
ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_ctx);
343+
if (ret)
344+
goto out;
345+
346+
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
347+
ret = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
348+
1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_uc_list) :
349+
1 << MLX5_GET(cmd_hca_cap, hca_caps, log_max_current_mc_list);
350+
351+
out:
352+
kfree(query_ctx);
353+
354+
return ret;
355+
}
356+
327357
int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
328358
u16 vport,
329359
enum mlx5_list_type list_type,
330-
u8 addr_list[][ETH_ALEN],
331-
int *list_size)
360+
u8 (**addr_list)[ETH_ALEN],
361+
int *addr_list_size)
332362
{
333363
u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {0};
364+
int allowed_list_size;
334365
void *nic_vport_ctx;
335366
int max_list_size;
336-
int req_list_size;
337367
int out_sz;
338368
void *out;
339369
int err;
340370
int i;
341371

342-
req_list_size = *list_size;
372+
if (!addr_list || !addr_list_size)
373+
return -EINVAL;
343374

344-
max_list_size = list_type == MLX5_NVPRT_LIST_TYPE_UC ?
345-
1 << MLX5_CAP_GEN(dev, log_max_current_uc_list) :
346-
1 << MLX5_CAP_GEN(dev, log_max_current_mc_list);
375+
*addr_list = NULL;
376+
*addr_list_size = 0;
347377

348-
if (req_list_size > max_list_size) {
349-
mlx5_core_warn(dev, "Requested list size (%d) > (%d) max_list_size\n",
350-
req_list_size, max_list_size);
351-
req_list_size = max_list_size;
352-
}
378+
max_list_size = mlx5_vport_max_mac_list_size(dev, vport, list_type);
379+
if (max_list_size < 0)
380+
return max_list_size;
353381

354382
out_sz = MLX5_ST_SZ_BYTES(query_nic_vport_context_out) +
355-
req_list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
383+
max_list_size * MLX5_ST_SZ_BYTES(mac_address_layout);
356384

357385
out = kvzalloc(out_sz, GFP_KERNEL);
358386
if (!out)
@@ -371,16 +399,24 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
371399

372400
nic_vport_ctx = MLX5_ADDR_OF(query_nic_vport_context_out, out,
373401
nic_vport_context);
374-
req_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
375-
allowed_list_size);
402+
allowed_list_size = MLX5_GET(nic_vport_context, nic_vport_ctx,
403+
allowed_list_size);
404+
if (!allowed_list_size)
405+
goto out;
406+
407+
*addr_list = kcalloc(allowed_list_size, ETH_ALEN, GFP_KERNEL);
408+
if (!*addr_list) {
409+
err = -ENOMEM;
410+
goto out;
411+
}
376412

377-
*list_size = req_list_size;
378-
for (i = 0; i < req_list_size; i++) {
413+
for (i = 0; i < allowed_list_size; i++) {
379414
u8 *mac_addr = MLX5_ADDR_OF(nic_vport_context,
380415
nic_vport_ctx,
381416
current_uc_mac_address[i]) + 2;
382-
ether_addr_copy(addr_list[i], mac_addr);
417+
ether_addr_copy((*addr_list)[i], mac_addr);
383418
}
419+
*addr_list_size = allowed_list_size;
384420
out:
385421
kvfree(out);
386422
return err;

include/linux/mlx5/vport.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev,
102102
int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev,
103103
u16 vport,
104104
enum mlx5_list_type list_type,
105-
u8 addr_list[][ETH_ALEN],
106-
int *list_size);
105+
u8 (**mac_list)[ETH_ALEN],
106+
int *mac_list_size);
107107
int mlx5_modify_nic_vport_mac_list(struct mlx5_core_dev *dev,
108108
enum mlx5_list_type list_type,
109109
u8 addr_list[][ETH_ALEN],

0 commit comments

Comments
 (0)