diff mbox series

[for-next] RDMA/core: Avoid panic when port_data isn't initialized

Message ID 20190522072340.9042-1-kamalheib1@gmail.com (mailing list archive)
State Changes Requested
Headers show
Series [for-next] RDMA/core: Avoid panic when port_data isn't initialized | expand

Commit Message

Kamal Heib May 22, 2019, 7:23 a.m. UTC
A panic could occur when calling ib_device_release() and port_data
isn't initialized, To avoid that a check was added to verify that
port_data isn't NULL.

Signed-off-by: Kamal Heib <kamalheib1@gmail.com>
---
 drivers/infiniband/core/cache.c    | 3 +++
 drivers/infiniband/core/device.c   | 3 +++
 drivers/infiniband/core/security.c | 3 +++
 3 files changed, 9 insertions(+)

Comments

Jason Gunthorpe May 22, 2019, 12:15 p.m. UTC | #1
On Wed, May 22, 2019 at 10:23:40AM +0300, Kamal Heib wrote:
> A panic could occur when calling ib_device_release() and port_data
> isn't initialized, To avoid that a check was added to verify that
> port_data isn't NULL.

This is a terrible commit message, describe the case that causes this.

The check should be in ib_device_release(), not in the functions.

Jason
Kamal Heib May 22, 2019, 12:42 p.m. UTC | #2
On Wed, 2019-05-22 at 09:15 -0300, Jason Gunthorpe wrote:
> On Wed, May 22, 2019 at 10:23:40AM +0300, Kamal Heib wrote:
> > A panic could occur when calling ib_device_release() and port_data
> > isn't initialized, To avoid that a check was added to verify that
> > port_data isn't NULL.
> 
> This is a terrible commit message, describe the case that causes
> this.
> 

This happen if assign_name() return failure when called from
ib_register_device() - The following panic will happen and in every
function that touches the port_data's data members.

[   33.668236] BUG: unable to handle kernel NULL pointer dereference at
00000000000000c0
[   33.668238] #PF error: [WRITE]
[   33.668239] PGD 0 P4D 0 
[   33.668241] Oops: 0002 [#1] SMP PTI
[   33.668244] CPU: 19 PID: 1994 Comm: systemd-udevd Not tainted 5.1.0-
rc5+ #1
[   33.668245] Hardware name: HP ProLiant DL360p Gen8, BIOS P71
12/20/2013
[   33.668252] RIP: 0010:_raw_spin_lock_irqsave+0x1e/0x40
[   33.668254] Code: 85 ff 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90
53 9c 58 66 66 90 66 90 48 89 c3 fa 66 66 90 66 66 90 31 c0 ba 01 00 00
00 <f0> 0f b1 17 0f 94 c2 84 d2 74 05 48 89 d8 5b c3 89 c6 e8 b4 85 8a
[   33.668254] RSP: 0018:ffffa8d7079a7c08 EFLAGS: 00010046
[   33.668256] RAX: 0000000000000000 RBX: 0000000000000202 RCX:
ffffa8d7079a7bf8
[   33.668256] RDX: 0000000000000001 RSI: ffff93607c990000 RDI:
00000000000000c0
[   33.668257] RBP: 0000000000000001 R08: 0000000000000000 R09:
ffffffffc08c4dd8
[   33.668258] R10: 0000000000000000 R11: 0000000000000001 R12:
00000000000000c0
[   33.668259] R13: ffff93607c990000 R14: ffffffffc05a9740 R15:
ffffa8d7079a7e98
[   33.668260] FS:  00007f1c6ee438c0(0000) GS:ffff93609f6c0000(0000)
knlGS:0000000000000000
[   33.668261] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   33.668261] CR2: 00000000000000c0 CR3: 0000000819fca002 CR4:
00000000000606e0
[   33.668262] Call Trace:
[   33.668280]  free_netdevs+0x4d/0xe0 [ib_core]
[   33.668289]  ib_dealloc_device+0x51/0xb0 [ib_core]
[   33.668300]  __mlx5_ib_add+0x5e/0x70 [mlx5_ib]
[   33.668321]  mlx5_add_device+0x57/0xe0 [mlx5_core]
[   33.668335]  mlx5_register_interface+0x85/0xc0 [mlx5_core]
[   33.668337]  ? 0xffffffffc0474000
[   33.668340]  do_one_initcall+0x4e/0x1d4
[   33.668342]  ? _cond_resched+0x15/0x30
[   33.668345]  ? kmem_cache_alloc_trace+0x15f/0x1c0
[   33.668348]  do_init_module+0x5a/0x218
[   33.668350]  load_module+0x186b/0x1e40
[   33.668351]  ? m_show+0x1c0/0x1c0
[   33.668354]  __do_sys_finit_module+0x94/0xe0
[   33.668356]  do_syscall_64+0x5b/0x180
[   33.668358]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   33.668360] RIP: 0033:0x7f1c6daa0be9
[   33.668361] Code: 01 00 48 81 c4 80 00 00 00 e9 f1 fe ff ff 0f 1f 00
48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f
05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 57 e2 2c 00 f7 d8 64 89 01 48
[   33.668362] RSP: 002b:00007ffd2d71a3e8 EFLAGS: 00000246 ORIG_RAX:
0000000000000139
[   33.668363] RAX: ffffffffffffffda RBX: 00005576c3936f60 RCX:
00007f1c6daa0be9
[   33.668364] RDX: 0000000000000000 RSI: 00007f1c6e3c2039 RDI:
000000000000000e
[   33.668364] RBP: 00007f1c6e3c2039 R08: 0000000000000000 R09:
00005576c39374c0
[   33.668365] R10: 000000000000000e R11: 0000000000000246 R12:
0000000000000000
[   33.668365] R13: 00005576c39fd9a0 R14: 0000000000020000 R15:
0000000000000000
[   33.668367] Modules linked in: mlx5_ib(+) kvm irqbypass ib_uverbs
ipmi_ssif crct10dif_pclmul ib_core crc32_pclmul ghash_clmulni_intel
ipmi_si aesni_intel iTCO_wdt iTCO_vendor_support crypto_simd cryptd
glue_helper hpilo sg ipmi_devintf pcspkr ioatdma ipmi_msghandler hpwdt
acpi_power_meter pcc_cpufreq dca lpc_ich ip_tables xfs libcrc32c
mgag200 ata_generic sd_mod pata_acpi i2c_algo_bit drm_kms_helper
mlx5_core syscopyarea sysfillrect sysimgblt fb_sys_fops ttm tg3 mlxfw
drm ata_piix hpsa ptp libata crc32c_intel serio_raw pps_core
scsi_transport_sas dm_mirror dm_region_hash dm_log dm_mod
[   33.668387] CR2: 00000000000000c0
[   33.668414] ---[ end trace e1a60554f6535c71 ]---
[   33.675166] XFS (sda1): Mounting V5 Filesystem
[   33.676498] RIP: 0010:_raw_spin_lock_irqsave+0x1e/0x40
[   33.676500] Code: 85 ff 66 2e 0f 1f 84 00 00 00 00 00 66 66 66 66 90
53 9c 58 66 66 90 66 90 48 89 c3 fa 66 66 90 66 66 90 31 c0 ba 01 00 00
00 <f0> 0f b1 17 0f 94 c2 84 d2 74 05 48 89 d8 5b c3 89 c6 e8 b4 85 8a
[   33.676500] RSP: 0018:ffffa8d7079a7c08 EFLAGS: 00010046
[   33.676501] RAX: 0000000000000000 RBX: 0000000000000202 RCX:
ffffa8d7079a7bf8
[   33.676502] RDX: 0000000000000001 RSI: ffff93607c990000 RDI:
00000000000000c0
[   33.676503] RBP: 0000000000000001 R08: 0000000000000000 R09:
ffffffffc08c4dd8
[   33.676503] R10: 0000000000000000 R11: 0000000000000001 R12:
00000000000000c0
[   33.676504] R13: ffff93607c990000 R14: ffffffffc05a9740 R15:
ffffa8d7079a7e98
[   33.676505] FS:  00007f1c6ee438c0(0000) GS:ffff93609f6c0000(0000)
knlGS:0000000000000000
[   33.676506] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   33.676507] CR2: 00000000000000c0 CR3: 0000000819fca002 CR4:
00000000000606e0
[   33.676508] Kernel panic - not syncing: Fatal exception
[   33.706833] Kernel Offset: 0x2b200000 from 0xffffffff81000000
(relocation range: 0xffffffff80000000-0xffffffffbfffffff)

> The check should be in ib_device_release(), not in the functions.
> 
> Jason

Why? 

static void ib_device_release(struct device *device)
{
	struct ib_device *dev = container_of(device, struct ib_device,
dev);

	free_netdevs(dev);
	WARN_ON(refcount_read(&dev->refcount));
	ib_cache_release_one(dev);
	ib_security_release_port_pkey_list(dev);
	xa_destroy(&dev->compat_devs);
	xa_destroy(&dev->client_data);
	if (dev->port_data)
		kfree_rcu(container_of(dev->port_data, struct
ib_port_data_rcu,
				       pdata[0]),
			  rcu_head);
	kfree_rcu(dev, rcu_head);
}

Thanks,
Kamal
Jason Gunthorpe May 22, 2019, 1:31 p.m. UTC | #3
On Wed, May 22, 2019 at 03:42:47PM +0300, Kamal Heib wrote:
> On Wed, 2019-05-22 at 09:15 -0300, Jason Gunthorpe wrote:
> > On Wed, May 22, 2019 at 10:23:40AM +0300, Kamal Heib wrote:
> > > A panic could occur when calling ib_device_release() and port_data
> > > isn't initialized, To avoid that a check was added to verify that
> > > port_data isn't NULL.
> > 
> > This is a terrible commit message, describe the case that causes
> > this.
> > 
> 
> This happen if assign_name() return failure when called from
> ib_register_device() - The following panic will happen and in every
> function that touches the port_data's data members.

Then this should be the commit message, with the oops.

> > The check should be in ib_device_release(), not in the functions.
> > 
> > Jason
>
> Why?

Because if the device has not progressed to be setup enough we
shouldn't be freeing things that aren't started yet.

However, it is a bit weird because the cache_release was intended to
not have dependencies - but the cache also can't be started until the
port_data is setup

The real problem is that we can't allocate the port data during
ib_alloc_device..

Jason
diff mbox series

Patch

diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 18e476b3ced0..87801e3848a8 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -1520,6 +1520,9 @@  void ib_cache_release_one(struct ib_device *device)
 {
 	unsigned int p;
 
+	if (!device->port_data)
+		return;
+
 	/*
 	 * The release function frees all the cache elements.
 	 * This function should be called as part of freeing
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 78dc07c6ac4b..3a497e57f673 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -1935,6 +1935,9 @@  static void free_netdevs(struct ib_device *ib_dev)
 	unsigned long flags;
 	unsigned int port;
 
+	if (!ib_dev->port_data)
+		return;
+
 	rdma_for_each_port (ib_dev, port) {
 		struct ib_port_data *pdata = &ib_dev->port_data[port];
 		struct net_device *ndev;
diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c
index 1ab423b19f77..fba7bd5d4a2e 100644
--- a/drivers/infiniband/core/security.c
+++ b/drivers/infiniband/core/security.c
@@ -564,6 +564,9 @@  void ib_security_release_port_pkey_list(struct ib_device *device)
 	struct pkey_index_qp_list *pkey, *tmp_pkey;
 	unsigned int i;
 
+	if (!device->port_data)
+		return;
+
 	rdma_for_each_port (device, i) {
 		list_for_each_entry_safe(pkey,
 					 tmp_pkey,