Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

RDMA/core: Check that type_attrs is not NULL prior access

In disassociate flow, the type_attrs is set to be NULL, which is in an
implicit way is checked in alloc_uobj() by "if (!attrs->context)".

Change the logic to rely on that check, to be consistent with other
alloc_uobj() places that will fix the following kernel splat.

BUG: kernel NULL pointer dereference, address: 0000000000000018
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: 0000 [#1] SMP PTI
CPU: 3 PID: 2743 Comm: python3 Not tainted 5.7.0-rc6-for-upstream-perf-2020-05-23_19-04-38-5 #1
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
RIP: 0010:alloc_begin_fd_uobject+0x18/0xf0 [ib_uverbs]
Code: 89 43 48 eb 97 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 41 55 49 89 f5 41 54 55 48 89 fd 53 48 83 ec 08 48 8b 1f <48> 8b 43 18 48 8b 80 80 00 00 00 48 3d 20 10 33 a0 74 1c 48 3d 30
RSP: 0018:ffffc90001127b70 EFLAGS: 00010282
RAX: ffffffffa0339fe0 RBX: 0000000000000000 RCX: 8000000000000007
RDX: fffffffffffffffb RSI: ffffc90001127d28 RDI: ffff88843fe1f600
RBP: ffff88843fe1f600 R08: ffff888461eb06d8 R09: ffff888461eb06f8
R10: ffff888461eb0700 R11: 0000000000000000 R12: ffff88846a5f6450
R13: ffffc90001127d28 R14: ffff88845d7d6ea0 R15: ffffc90001127cb8
FS: 00007f469bff1540(0000) GS:ffff88846f980000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000018 CR3: 0000000450018003 CR4: 0000000000760ee0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
PKRU: 55555554
Call Trace:
? xa_store+0x28/0x40
rdma_alloc_begin_uobject+0x4f/0x90 [ib_uverbs]
ib_uverbs_create_comp_channel+0x87/0xf0 [ib_uverbs]
ib_uverbs_handler_UVERBS_METHOD_INVOKE_WRITE+0xb1/0xf0 [ib_uverbs]
ib_uverbs_cmd_verbs.isra.8+0x96d/0xae0 [ib_uverbs]
? get_page_from_freelist+0x3bb/0xf70
? _copy_to_user+0x22/0x30
? uverbs_disassociate_api+0xd0/0xd0 [ib_uverbs]
? __wake_up_common_lock+0x87/0xc0
ib_uverbs_ioctl+0xbc/0x130 [ib_uverbs]
ksys_ioctl+0x83/0xc0
? ksys_write+0x55/0xd0
__x64_sys_ioctl+0x16/0x20
do_syscall_64+0x48/0x130
entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x7f469ac43267

Fixes: 849e149063bd ("RDMA/core: Do not allow alloc_commit to fail")
Link: https://lore.kernel.org/r/20200617061826.2625359-1-leon@kernel.org
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>

authored by

Leon Romanovsky and committed by
Jason Gunthorpe
4121fb0d 3ec5f54f

+22 -16
+22 -16
drivers/infiniband/core/rdma_core.c
··· 470 470 alloc_begin_fd_uobject(const struct uverbs_api_object *obj, 471 471 struct uverbs_attr_bundle *attrs) 472 472 { 473 - const struct uverbs_obj_fd_type *fd_type = 474 - container_of(obj->type_attrs, struct uverbs_obj_fd_type, type); 473 + const struct uverbs_obj_fd_type *fd_type; 475 474 int new_fd; 476 - struct ib_uobject *uobj; 475 + struct ib_uobject *uobj, *ret; 477 476 struct file *filp; 478 - 479 - if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release && 480 - fd_type->fops->release != &uverbs_async_event_release)) 481 - return ERR_PTR(-EINVAL); 482 - 483 - new_fd = get_unused_fd_flags(O_CLOEXEC); 484 - if (new_fd < 0) 485 - return ERR_PTR(new_fd); 486 477 487 478 uobj = alloc_uobj(attrs, obj); 488 479 if (IS_ERR(uobj)) 480 + return uobj; 481 + 482 + fd_type = 483 + container_of(obj->type_attrs, struct uverbs_obj_fd_type, type); 484 + if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release && 485 + fd_type->fops->release != &uverbs_async_event_release)) { 486 + ret = ERR_PTR(-EINVAL); 489 487 goto err_fd; 488 + } 489 + 490 + new_fd = get_unused_fd_flags(O_CLOEXEC); 491 + if (new_fd < 0) { 492 + ret = ERR_PTR(new_fd); 493 + goto err_fd; 494 + } 490 495 491 496 /* Note that uverbs_uobject_fd_release() is called during abort */ 492 497 filp = anon_inode_getfile(fd_type->name, fd_type->fops, NULL, 493 498 fd_type->flags); 494 499 if (IS_ERR(filp)) { 495 - uverbs_uobject_put(uobj); 496 - uobj = ERR_CAST(filp); 497 - goto err_fd; 500 + ret = ERR_CAST(filp); 501 + goto err_getfile; 498 502 } 499 503 uobj->object = filp; 500 504 501 505 uobj->id = new_fd; 502 506 return uobj; 503 507 504 - err_fd: 508 + err_getfile: 505 509 put_unused_fd(new_fd); 506 - return uobj; 510 + err_fd: 511 + uverbs_uobject_put(uobj); 512 + return ret; 507 513 } 508 514 509 515 struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,