Commit
467f432a521a ("RDMA/core: Split port and device counter sysfs
attributes") accidentally almost exposed hw counters to non-init net
namespaces. It didn't expose them fully, as an attempt to read any of
those counters leads to a crash like this one:
[42021.807566] BUG: kernel NULL pointer dereference, address:
0000000000000028
[42021.814463] #PF: supervisor read access in kernel mode
[42021.819549] #PF: error_code(0x0000) - not-present page
[42021.824636] PGD 0 P4D 0
[42021.827145] Oops: 0000 [#1] SMP PTI
[42021.830598] CPU: 82 PID:
2843922 Comm: switchto-defaul Kdump: loaded Tainted: G S W I XXX
[42021.841697] Hardware name: XXX
[42021.849619] RIP: 0010:hw_stat_device_show+0x1e/0x40 [ib_core]
[42021.855362] Code: 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 49 89 d0 4c 8b 5e 20 48 8b 8f b8 04 00 00 48 81 c7 f0 fa ff ff <48> 8b 41 28 48 29 ce 48 83 c6 d0 48 c1 ee 04 69 d6 ab aa aa aa 48
[42021.873931] RSP: 0018:
ffff97fe90f03da0 EFLAGS:
00010287
[42021.879108] RAX:
ffff9406988a8c60 RBX:
ffff940e1072d438 RCX:
0000000000000000
[42021.886169] RDX:
ffff94085f1aa000 RSI:
ffff93c6cbbdbcb0 RDI:
ffff940c7517aef0
[42021.893230] RBP:
ffff97fe90f03e70 R08:
ffff94085f1aa000 R09:
0000000000000000
[42021.900294] R10:
ffff94085f1aa000 R11:
ffffffffc0775680 R12:
ffffffff87ca2530
[42021.907355] R13:
ffff940651602840 R14:
ffff93c6cbbdbcb0 R15:
ffff94085f1aa000
[42021.914418] FS:
00007fda1a3b9700(0000) GS:
ffff94453fb80000(0000) knlGS:
0000000000000000
[42021.922423] CS: 0010 DS: 0000 ES: 0000 CR0:
0000000080050033
[42021.928130] CR2:
0000000000000028 CR3:
00000042dcfb8003 CR4:
00000000003726f0
[42021.935194] DR0:
0000000000000000 DR1:
0000000000000000 DR2:
0000000000000000
[42021.942257] DR3:
0000000000000000 DR6:
00000000fffe0ff0 DR7:
0000000000000400
[42021.949324] Call Trace:
[42021.951756] <TASK>
[42021.953842] [<
ffffffff86c58674>] ? show_regs+0x64/0x70
[42021.959030] [<
ffffffff86c58468>] ? __die+0x78/0xc0
[42021.963874] [<
ffffffff86c9ef75>] ? page_fault_oops+0x2b5/0x3b0
[42021.969749] [<
ffffffff87674b92>] ? exc_page_fault+0x1a2/0x3c0
[42021.975549] [<
ffffffff87801326>] ? asm_exc_page_fault+0x26/0x30
[42021.981517] [<
ffffffffc0775680>] ? __pfx_show_hw_stats+0x10/0x10 [ib_core]
[42021.988482] [<
ffffffffc077564e>] ? hw_stat_device_show+0x1e/0x40 [ib_core]
[42021.995438] [<
ffffffff86ac7f8e>] dev_attr_show+0x1e/0x50
[42022.000803] [<
ffffffff86a3eeb1>] sysfs_kf_seq_show+0x81/0xe0
[42022.006508] [<
ffffffff86a11134>] seq_read_iter+0xf4/0x410
[42022.011954] [<
ffffffff869f4b2e>] vfs_read+0x16e/0x2f0
[42022.017058] [<
ffffffff869f50ee>] ksys_read+0x6e/0xe0
[42022.022073] [<
ffffffff8766f1ca>] do_syscall_64+0x6a/0xa0
[42022.027441] [<
ffffffff8780013b>] entry_SYSCALL_64_after_hwframe+0x78/0xe2
The problem can be reproduced using the following steps:
ip netns add foo
ip netns exec foo bash
cat /sys/class/infiniband/mlx4_0/hw_counters/*
The panic occurs because of casting the device pointer into an
ib_device pointer using container_of() in hw_stat_device_show() is
wrong and leads to a memory corruption.
However the real problem is that hw counters should never been exposed
outside of the non-init net namespace.
Fix this by saving the index of the corresponding attribute group
(it might be 1 or 2 depending on the presence of driver-specific
attributes) and zeroing the pointer to hw_counters group for compat
devices during the initialization.
With this fix applied hw_counters are not available in a non-init
net namespace:
find /sys/class/infiniband/mlx4_0/ -name hw_counters
/sys/class/infiniband/mlx4_0/ports/1/hw_counters
/sys/class/infiniband/mlx4_0/ports/2/hw_counters
/sys/class/infiniband/mlx4_0/hw_counters
ip netns add foo
ip netns exec foo bash
find /sys/class/infiniband/mlx4_0/ -name hw_counters
Fixes: 467f432a521a ("RDMA/core: Split port and device counter sysfs attributes")
Signed-off-by: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Maher Sanalla <msanalla@nvidia.com>
Cc: linux-rdma@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: https://patch.msgid.link/20250227165420.3430301-1-roman.gushchin@linux.dev
Reviewed-by: Parav Pandit <parav@nvidia.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
static void rdma_init_coredev(struct ib_core_device *coredev,
struct ib_device *dev, struct net *net)
{
+ bool is_full_dev = &dev->coredev == coredev;
+
/* This BUILD_BUG_ON is intended to catch layout change
* of union of ib_core_device and device.
* dev must be the first element as ib_core and providers
coredev->dev.class = &ib_class;
coredev->dev.groups = dev->groups;
+
+ /*
+ * Don't expose hw counters outside of the init namespace.
+ */
+ if (!is_full_dev && dev->hw_stats_attr_index)
+ coredev->dev.groups[dev->hw_stats_attr_index] = NULL;
+
device_initialize(&coredev->dev);
coredev->owner = dev;
INIT_LIST_HEAD(&coredev->port_list);
for (i = 0; i != ARRAY_SIZE(ibdev->groups); i++)
if (!ibdev->groups[i]) {
ibdev->groups[i] = &data->group;
+ ibdev->hw_stats_attr_index = i;
return 0;
}
WARN(true, "struct ib_device->groups is too small");
* It is a NULL terminated array.
*/
const struct attribute_group *groups[4];
+ u8 hw_stats_attr_index;
u64 uverbs_cmd_mask;