[SRU][F][PATCH v2 2/3] io_uring: dont kill fasync under completion_lock
Chengen Du
chengen.du at canonical.com
Tue Nov 26 04:14:27 UTC 2024
From: Pavel Begunkov <asml.silence at gmail.com>
CVE-2023-21400
BugLink: https://bugs.launchpad.net/bugs/2078659
CPU0 CPU1
---- ----
lock(&new->fa_lock);
local_irq_disable();
lock(&ctx->completion_lock);
lock(&new->fa_lock);
<Interrupt>
lock(&ctx->completion_lock);
*** DEADLOCK ***
Move kill_fasync() out of io_commit_cqring() to io_cqring_ev_posted(),
so it doesn't hold completion_lock while doing it. That saves from the
reported deadlock, and it's just nice to shorten the locking time and
untangle nested locks (compl_lock -> wq_head::lock).
Reported-by: syzbot+91ca3f25bd7f795f019c at syzkaller.appspotmail.com
Signed-off-by: Pavel Begunkov <asml.silence at gmail.com>
Signed-off-by: Jens Axboe <axboe at kernel.dk>
(backported from commit 4aa84f2ffa81f71e15e5cffc2cc6090dbee78f8e)
[chengen - introduce the io_cqring_ev_posted_iopoll function to handle
the kill_fasync logic in the io_iopoll_complete function.]
Signed-off-by: Chengen Du <chengen.du at canonical.com>
---
fs/io_uring.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index f90b159bfc3a..ce809ea55c6d 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -514,11 +514,6 @@ static void __io_commit_cqring(struct io_ring_ctx *ctx)
/* order cqe stores with ring update */
smp_store_release(&rings->cq.tail, ctx->cached_cq_tail);
-
- if (wq_has_sleeper(&ctx->cq_wait)) {
- wake_up_interruptible(&ctx->cq_wait);
- kill_fasync(&ctx->cq_fasync, SIGIO, POLL_IN);
- }
}
static inline void io_queue_async_work(struct io_ring_ctx *ctx,
@@ -639,6 +634,18 @@ static void io_cqring_ev_posted(struct io_ring_ctx *ctx)
wake_up(&ctx->sqo_wait);
if (ctx->cq_ev_fd)
eventfd_signal(ctx->cq_ev_fd, 1);
+ if (wq_has_sleeper(&ctx->cq_wait)) {
+ wake_up_interruptible(&ctx->cq_wait);
+ kill_fasync(&ctx->cq_fasync, SIGIO, POLL_IN);
+ }
+}
+
+static void io_cqring_ev_posted_iopoll(struct io_ring_ctx *ctx)
+{
+ if (wq_has_sleeper(&ctx->cq_wait)) {
+ wake_up_interruptible(&ctx->cq_wait);
+ kill_fasync(&ctx->cq_fasync, SIGIO, POLL_IN);
+ }
}
static void io_cqring_add_event(struct io_ring_ctx *ctx, u64 user_data,
@@ -840,6 +847,7 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
}
io_commit_cqring(ctx);
+ io_cqring_ev_posted_iopoll(ctx);
io_free_req_many(ctx, reqs, &to_free);
}
--
2.43.0
More information about the kernel-team
mailing list