mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
RDMA/ucma: Lock the handler in ucma_write_cm_event()
ctx->file may only be changed under the handler lock and the xa_lock, which
is what stops uevents being queued for a ctx while ucma_migrate_id() moves
it to another file. The CM core takes that lock before invoking
ucma_event_handler(), but the write() paths that queue uevents themselves
do not.
ucma_write_cm_event() re-reads ctx->file for each of its four dereferences,
so ucma_migrate_id() can swap it mid-sequence:
mutex_lock(&ctx->file->mut); /* file A */
list_add_tail(&uevent->list, &ctx->file->event_list); /* file B */
mutex_unlock(&ctx->file->mut); /* file B */
wake_up_interruptible(&ctx->file->poll_wait); /* file B */
The window is the mutex_lock() itself: the writer sleeps in it while the
migration reassigns ctx->file. The list_add_tail() then runs on file B's
event_list holding only file A's mutex:
list_add corruption. prev->next should be next (ffff888101320f30),
but was ffff88814a08c418. (prev=ffff88814a075c18).
kernel BUG at lib/list_debug.c:32!
Call Trace:
ucma_write_cm_event+0x36e/0x5e0
and file A's mut is left held forever, wedging its next writer in D state.
The uevent is also stranded on a list ucma_cleanup_ctx_events() will not
walk, so it outlives its context. /dev/infiniband/rdma_cm is 0666 and no
RDMA device is involved, so an unprivileged user reaches all of this.
Take the handler lock, as ucma_cleanup_mc_events() does; ctx->cm_id is
pinned by the ucma_get_ctx() reference.
Fixes: a3c9d0fcd3 ("RDMA/ucma: Support write an event into a CM")
Link: https://patch.msgid.link/r/60544A67-EFD6-4D5D-974C-D983445F1070@doyensec.com
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
a12d914514
commit
f4cc21c6a8
|
|
@ -1776,6 +1776,13 @@ static ssize_t ucma_write_cm_event(struct ucma_file *file,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rdma_lock_handler(ctx->cm_id);
|
||||
if (!ctx->uid) {
|
||||
kfree(uevent);
|
||||
ret = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
uevent->ctx = ctx;
|
||||
uevent->resp.uid = ctx->uid;
|
||||
uevent->resp.id = ctx->id;
|
||||
|
|
@ -1789,6 +1796,8 @@ static ssize_t ucma_write_cm_event(struct ucma_file *file,
|
|||
mutex_unlock(&ctx->file->mut);
|
||||
wake_up_interruptible(&ctx->file->poll_wait);
|
||||
|
||||
err_unlock:
|
||||
rdma_unlock_handler(ctx->cm_id);
|
||||
out:
|
||||
ucma_put_ctx(ctx);
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user