From 00c1a53b2091d44cfea67d621d6e7f362faffea6 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Tue, 12 Jun 2012 13:34:22 +0300 Subject: [PATCH] ib_core: fix NULL pointer dereference If there was a failure in the initial fill of the Pkey/GID cache, and some other ULP/module will try to query a Pkey/GID, the NULL pointer will be dereferenced, thing that will lead to the following kernel panic: BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 IP: [] _spin_lock_irqsave+0x1f/0x40 PGD 37b49067 PUD becb3067 PMD 0 Oops: 0002 [#1] SMP last sysfs file: /sys/module/mlx4_core/initstate CPU 1 Modules linked in: mlx4_ib(+)(U) ib_sa(U) ib_mad(U) ib_core(U) mlx4_en(U) mlx4_core(U) memtrack(U) netconsole configfs nfs fscache nfsd lockd nfs_acl auth_rpcgss exportfs autofs4 sunrpc ipv6 knem(U) microcode virtio_balloon virtio_net snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore snd_page_alloc i2c_piix4 i2c_core ext3 jbd mbcache virtio_blk virtio_pci virtio_ring virtio pata_acpi ata_generic ata_piix dm_mirror dm_region_hash dm_log dm_mod [last unloaded: memtrack] Pid: 20715, comm: modprobe Not tainted 2.6.32-220.el6.x86_64 #1 Red Hat KVM RIP: 0010:[] [] _spin_lock_irqsave+0x1f/0x40 RSP: 0018:ffff8800bc331d08 EFLAGS: 00010002 RAX: 0000000000010000 RBX: ffff8800bec00088 RCX: 0000000000000000 RDX: 0000000000000202 RSI: 0000000000000046 RDI: 0000000000000058 RBP: ffff8800bc331d08 R08: 0000000000000000 R09: ffff88011bde8050 R10: ffff8800bc3317d8 R11: 0000000000000002 R12: ffff8800b9520000 R13: ffff8800bec00000 R14: 0000000000000000 R15: ffff8800bec02c00 FS: 00007f2f07fcd700(0000) GS:ffff880028300000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000058 CR3: 00000000bb708000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 20715, threadinfo ffff8800bc330000, task ffff8801185e0b40) Stack: ffff8800bc331d28 ffffffffa0244ee5 ffff8800bec00000 ffff8800b9520000 <0> ffff8800bc331d68 ffffffffa0246f96 0000000000000370 ffffffffa0359560 <0> ffffffffa024fde0 ffff8800b9520000 ffff8800bec00000 ffff8800bcf36080 Call Trace: [] ib_unregister_event_handler+0x25/0x50 [ib_core] [] ib_cache_cleanup_one+0x26/0x1b0 [ib_core] [] ib_unregister_device+0x4e/0x1a0 [ib_core] [] ? mlx4_ib_mad_init+0xa6/0x170 [mlx4_ib] [] mlx4_ib_add+0x621/0xb80 [mlx4_ib] [] mlx4_add_device+0x73/0x1d0 [mlx4_core] [] mlx4_register_interface+0x7b/0x100 [mlx4_core] [] mlx4_ib_init+0x12a/0x188 [mlx4_ib] [] ? mlx4_ib_init+0x0/0x188 [mlx4_ib] [] do_one_initcall+0x3c/0x1d0 [] sys_init_module+0xe1/0x250 [] system_call_fastpath+0x16/0x1b Code: c9 c3 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 0f 1f 44 00 00 9c 58 0f 1f 44 00 00 48 89 c2 fa 66 0f 1f 44 00 00 b8 00 00 01 00 0f c1 07 0f b7 c8 c1 e8 10 39 c1 74 0e f3 90 0f 1f 44 00 00 RIP [] _spin_lock_irqsave+0x1f/0x40 RSP CR2: 0000000000000058 ---[ end trace 4cc9b3e738027b7c ]--- Kernel panic - not syncing: Fatal exception Pid: 20715, comm: modprobe Tainted: G D ---------------- 2.6.32-220.el6.x86_64 #1 Call Trace: [] ? panic+0x78/0x143 [] ? oops_end+0xe4/0x100 [] ? no_context+0xfb/0x260 [] ? start_xmit+0x5d/0x1d0 [virtio_net] [] ? __bad_area_nosemaphore+0x125/0x1e0 [] ? bad_area+0x4e/0x60 [] ? __do_page_fault+0x3c3/0x480 [] ? write_msg+0xfd/0x110 [netconsole] [] ? __call_console_drivers+0x75/0x90 [] ? up+0x2f/0x50 [] ? _call_console_drivers+0x4a/0x80 [] ? do_page_fault+0x3e/0xa0 [] ? page_fault+0x25/0x30 [] ? _spin_lock_irqsave+0x1f/0x40 [] ? ib_unregister_event_handler+0x25/0x50 [ib_core] [] ? ib_cache_cleanup_one+0x26/0x1b0 [ib_core] [] ? ib_unregister_device+0x4e/0x1a0 [ib_core] [] ? mlx4_ib_mad_init+0xa6/0x170 [mlx4_ib] [] ? mlx4_ib_add+0x621/0xb80 [mlx4_ib] [] ? mlx4_add_device+0x73/0x1d0 [mlx4_core] [] ? mlx4_register_interface+0x7b/0x100 [mlx4_core] [] ? mlx4_ib_init+0x12a/0x188 [mlx4_ib] [] ? mlx4_ib_init+0x0/0x188 [mlx4_ib] [] ? do_one_initcall+0x3c/0x1d0 [] ? sys_init_module+0xe1/0x250 [] ? system_call_fastpath+0x16/0x1b Signed-off-by: Dotan Barak Reviewed-by: Eli Cohen (Ported from Mellanox OFED 2.4) Signed-off-by: Mukesh Kacker --- drivers/infiniband/core/cache.c | 42 ++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 80f6cf2449fb..e269a01e871f 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -76,19 +76,21 @@ int ib_get_cached_gid(struct ib_device *device, { struct ib_gid_cache *cache; unsigned long flags; - int ret = 0; + int ret = -EINVAL; if (port_num < start_port(device) || port_num > end_port(device)) return -EINVAL; read_lock_irqsave(&device->cache.lock, flags); - cache = device->cache.gid_cache[port_num - start_port(device)]; + if (device->cache.gid_cache) { + cache = device->cache.gid_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *gid = cache->table[index]; + if (cache && index >= 0 && index < cache->table_len) { + *gid = cache->table[index]; + ret = 0; + } + } read_unlock_irqrestore(&device->cache.lock, flags); @@ -138,19 +140,21 @@ int ib_get_cached_pkey(struct ib_device *device, { struct ib_pkey_cache *cache; unsigned long flags; - int ret = 0; + int ret = -EINVAL; if (port_num < start_port(device) || port_num > end_port(device)) return -EINVAL; read_lock_irqsave(&device->cache.lock, flags); - cache = device->cache.pkey_cache[port_num - start_port(device)]; + if (device->cache.pkey_cache) { + cache = device->cache.pkey_cache[port_num - start_port(device)]; - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *pkey = cache->table[index]; + if (cache && index >= 0 && index < cache->table_len) { + *pkey = cache->table[index]; + ret = 0; + } + } read_unlock_irqrestore(&device->cache.lock, flags); @@ -236,13 +240,16 @@ int ib_get_cached_lmc(struct ib_device *device, u8 *lmc) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; if (port_num < start_port(device) || port_num > end_port(device)) return -EINVAL; read_lock_irqsave(&device->cache.lock, flags); - *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + if (device->cache.lmc_cache) { + *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + ret = 0; + } read_unlock_irqrestore(&device->cache.lock, flags); return ret; @@ -403,12 +410,19 @@ err: kfree(device->cache.pkey_cache); kfree(device->cache.gid_cache); kfree(device->cache.lmc_cache); + device->cache.pkey_cache = NULL; + device->cache.gid_cache = NULL; + device->cache.lmc_cache = NULL; } static void ib_cache_cleanup_one(struct ib_device *device) { int p; + if (!(device->cache.pkey_cache && device->cache.gid_cache && + device->cache.lmc_cache)) + return; + ib_unregister_event_handler(&device->cache.event_handler); flush_workqueue(ib_wq); -- 2.50.1