Skip to content

Commit c4b5b49

Browse files
jgunthorpemarcelocerri
authored andcommitted
RDMA/core: Fix double destruction of uobject
BugLink: https://bugs.launchpad.net/bugs/1881927 [ Upstream commit c85f4ab ] Fix use after free when user user space request uobject concurrently for the same object, within the RCU grace period. In that case, remove_handle_idr_uobject() is called twice and we will have an extra put on the uobject which cause use after free. Fix it by leaving the uobject write locked after it was removed from the idr. Call to rdma_lookup_put_uobject with UVERBS_LOOKUP_DESTROY instead of UVERBS_LOOKUP_WRITE will do the work. refcount_t: underflow; use-after-free. WARNING: CPU: 0 PID: 1381 at lib/refcount.c:28 refcount_warn_saturate+0xfe/0x1a0 Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 1381 Comm: syz-executor.0 Not tainted 5.5.0-rc3 #8 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack+0x94/0xce panic+0x234/0x56f __warn+0x1cc/0x1e1 report_bug+0x200/0x310 fixup_bug.part.11+0x32/0x80 do_error_trap+0xd3/0x100 do_invalid_op+0x31/0x40 invalid_op+0x1e/0x30 RIP: 0010:refcount_warn_saturate+0xfe/0x1a0 Code: 0f 0b eb 9b e8 23 f6 6d ff 80 3d 6c d4 19 03 00 75 8d e8 15 f6 6d ff 48 c7 c7 c0 02 55 bd c6 05 57 d4 19 03 01 e8 a2 58 49 ff <0f> 0b e9 6e ff ff ff e8 f6 f5 6d ff 80 3d 42 d4 19 03 00 0f 85 5c RSP: 0018:ffffc90002df7b98 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff88810f6a193c RCX: ffffffffba649009 RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff88811b0283cc RBP: 0000000000000003 R08: ffffed10236060e3 R09: ffffed10236060e3 R10: 0000000000000001 R11: ffffed10236060e2 R12: ffff88810f6a193c R13: ffffc90002df7d60 R14: 0000000000000000 R15: ffff888116ae6a08 uverbs_uobject_put+0xfd/0x140 __uobj_perform_destroy+0x3d/0x60 ib_uverbs_close_xrcd+0x148/0x170 ib_uverbs_write+0xaa5/0xdf0 __vfs_write+0x7c/0x100 vfs_write+0x168/0x4a0 ksys_write+0xc8/0x200 do_syscall_64+0x9c/0x390 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x465b49 Code: f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 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 c7 c1 bc ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f759d122c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 000000000073bfa8 RCX: 0000000000465b49 RDX: 000000000000000c RSI: 0000000020000080 RDI: 0000000000000003 RBP: 0000000000000003 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f759d1236bc R13: 00000000004ca27c R14: 000000000070de40 R15: 00000000ffffffff Dumping ftrace buffer: (ftrace buffer empty) Kernel Offset: 0x39400000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) Fixes: 7452a3c ("IB/uverbs: Allow RDMA_REMOVE_DESTROY to work concurrently with disassociate") Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Maor Gottlieb <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Khalid Elmously <[email protected]>
1 parent 6c1653e commit c4b5b49

File tree

2 files changed

+14
-8
lines changed

2 files changed

+14
-8
lines changed

drivers/infiniband/core/rdma_core.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
160160
uobj->context = NULL;
161161

162162
/*
163-
* For DESTROY the usecnt is held write locked, the caller is expected
164-
* to put it unlock and put the object when done with it. Only DESTROY
165-
* can remove the IDR handle.
163+
* For DESTROY the usecnt is not changed, the caller is expected to
164+
* manage it via uobj_put_destroy(). Only DESTROY can remove the IDR
165+
* handle.
166166
*/
167167
if (reason != RDMA_REMOVE_DESTROY)
168168
atomic_set(&uobj->usecnt, 0);
@@ -194,7 +194,7 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
194194
/*
195195
* This calls uverbs_destroy_uobject() using the RDMA_REMOVE_DESTROY
196196
* sequence. It should only be used from command callbacks. On success the
197-
* caller must pair this with rdma_lookup_put_uobject(LOOKUP_WRITE). This
197+
* caller must pair this with uobj_put_destroy(). This
198198
* version requires the caller to have already obtained an
199199
* LOOKUP_DESTROY uobject kref.
200200
*/
@@ -205,6 +205,13 @@ int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
205205

206206
down_read(&ufile->hw_destroy_rwsem);
207207

208+
/*
209+
* Once the uobject is destroyed by RDMA_REMOVE_DESTROY then it is left
210+
* write locked as the callers put it back with UVERBS_LOOKUP_DESTROY.
211+
* This is because any other concurrent thread can still see the object
212+
* in the xarray due to RCU. Leaving it locked ensures nothing else will
213+
* touch it.
214+
*/
208215
ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE);
209216
if (ret)
210217
goto out_unlock;
@@ -223,7 +230,7 @@ int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
223230
/*
224231
* uobj_get_destroy destroys the HW object and returns a handle to the uobj
225232
* with a NULL object pointer. The caller must pair this with
226-
* uverbs_put_destroy.
233+
* uobj_put_destroy().
227234
*/
228235
struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
229236
u32 id, struct uverbs_attr_bundle *attrs)
@@ -257,8 +264,7 @@ int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
257264
uobj = __uobj_get_destroy(obj, id, attrs);
258265
if (IS_ERR(uobj))
259266
return PTR_ERR(uobj);
260-
261-
rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
267+
uobj_put_destroy(uobj);
262268
return 0;
263269
}
264270

include/rdma/uverbs_std_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
8888

8989
static inline void uobj_put_destroy(struct ib_uobject *uobj)
9090
{
91-
rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
91+
rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY);
9292
}
9393

9494
static inline void uobj_put_read(struct ib_uobject *uobj)

0 commit comments

Comments
 (0)