From: Pavel Begunkov asml.silence@gmail.com
mainline inclusion from mainline-5.11-rc1 commit 1a38ffc9cbca361cc274d6e234f5ef8922f0b6d9 category: bugfix bugzilla: 167380 CVE: NA
---------------------------
SQPOLL task may find sqo_task->files == NULL and __io_sq_thread_acquire_files() would leave it unset, so following fget_many() and others try to dereference NULL and fault. Propagate an error files are missing.
[ 118.962785] BUG: kernel NULL pointer dereference, address: 0000000000000020 [ 118.963812] #PF: supervisor read access in kernel mode [ 118.964534] #PF: error_code(0x0000) - not-present page [ 118.969029] RIP: 0010:__fget_files+0xb/0x80 [ 119.005409] Call Trace: [ 119.005651] fget_many+0x2b/0x30 [ 119.005964] io_file_get+0xcf/0x180 [ 119.006315] io_submit_sqes+0x3a4/0x950 [ 119.007481] io_sq_thread+0x1de/0x6a0 [ 119.007828] kthread+0x114/0x150 [ 119.008963] ret_from_fork+0x22/0x30
Reported-by: Josef Grieb josef.grieb@gmail.com Signed-off-by: Pavel Begunkov asml.silence@gmail.com Signed-off-by: Jens Axboe axboe@kernel.dk
Conflicts: fs/io_uring.c [ aa1a90087b("io_uring: allow non-fixed files with SQPOLL") merge conflicts. ]
Signed-off-by: Zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/io_uring.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index f661231cdfad6..c944a27178a48 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -978,7 +978,7 @@ static void io_sq_thread_drop_mm_files(void) } }
-static void __io_sq_thread_acquire_files(struct io_ring_ctx *ctx) +static int __io_sq_thread_acquire_files(struct io_ring_ctx *ctx) { if (!current->files) { struct files_struct *files; @@ -988,7 +988,7 @@ static void __io_sq_thread_acquire_files(struct io_ring_ctx *ctx) files = ctx->sqo_task->files; if (!files) { task_unlock(ctx->sqo_task); - return; + return -EOWNERDEAD; } atomic_inc(&files->count); get_nsproxy(ctx->sqo_task->nsproxy); @@ -1000,6 +1000,7 @@ static void __io_sq_thread_acquire_files(struct io_ring_ctx *ctx) current->nsproxy = nsproxy; task_unlock(current); } + return 0; }
static int __io_sq_thread_acquire_mm(struct io_ring_ctx *ctx) @@ -1031,15 +1032,19 @@ static int io_sq_thread_acquire_mm_files(struct io_ring_ctx *ctx, struct io_kiocb *req) { const struct io_op_def *def = &io_op_defs[req->opcode]; + int ret;
if (def->needs_mm) { - int ret = __io_sq_thread_acquire_mm(ctx); + ret = __io_sq_thread_acquire_mm(ctx); if (unlikely(ret)) return ret; }
- if (def->needs_file || def->file_table) - __io_sq_thread_acquire_files(ctx); + if (def->needs_file || def->file_table) { + ret = __io_sq_thread_acquire_files(ctx); + if (unlikely(ret)) + return ret; + }
return 0; } @@ -1878,8 +1883,8 @@ static void __io_req_task_submit(struct io_kiocb *req) { struct io_ring_ctx *ctx = req->ctx;
- if (!__io_sq_thread_acquire_mm(ctx)) { - __io_sq_thread_acquire_files(ctx); + if (!__io_sq_thread_acquire_mm(ctx) && + !__io_sq_thread_acquire_files(ctx)) { mutex_lock(&ctx->uring_lock); __io_queue_sqe(req, NULL, NULL); mutex_unlock(&ctx->uring_lock);