If we don't inherit the original task creds, then we can confuse users like fuse that pass creds in the request header. See link below on identical aio issue. Link: https://lore.kernel.org/linux-fsdevel/26f0d78e-99ca-2f1b-78b9-433088053a61@xxxxxxxxxxxx/T/#u Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- fs/io_uring.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/io_uring.c b/fs/io_uring.c index 84efb8956734..9bead1717949 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -255,6 +255,8 @@ struct io_ring_ctx { struct user_struct *user; + struct cred *creds; + struct completion ctx_done; struct { @@ -1294,8 +1296,11 @@ static void io_poll_complete_work(struct work_struct *work) struct io_poll_iocb *poll = &req->poll; struct poll_table_struct pt = { ._key = poll->events }; struct io_ring_ctx *ctx = req->ctx; + const struct cred *old_cred; __poll_t mask = 0; + old_cred = override_creds(ctx->creds); + if (!READ_ONCE(poll->canceled)) mask = vfs_poll(poll->file, &pt) & poll->events; @@ -1310,7 +1315,7 @@ static void io_poll_complete_work(struct work_struct *work) if (!mask && !READ_ONCE(poll->canceled)) { add_wait_queue(poll->head, &poll->wait); spin_unlock_irq(&ctx->completion_lock); - return; + goto out; } list_del_init(&req->list); io_poll_complete(ctx, req, mask); @@ -1318,6 +1323,8 @@ static void io_poll_complete_work(struct work_struct *work) io_cqring_ev_posted(ctx); io_put_req(req); +out: + revert_creds(old_cred); } static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, @@ -1528,10 +1535,12 @@ static void io_sq_wq_submit_work(struct work_struct *work) struct io_ring_ctx *ctx = req->ctx; struct mm_struct *cur_mm = NULL; struct async_list *async_list; + const struct cred *old_cred; LIST_HEAD(req_list); mm_segment_t old_fs; int ret; + old_cred = override_creds(ctx->creds); async_list = io_async_list_from_sqe(ctx, req->submit.sqe); restart: do { @@ -1633,6 +1642,7 @@ static void io_sq_wq_submit_work(struct work_struct *work) unuse_mm(cur_mm); mmput(cur_mm); } + revert_creds(old_cred); } /* @@ -1881,6 +1891,7 @@ static int io_sq_thread(void *data) struct sqe_submit sqes[IO_IOPOLL_BATCH]; struct io_ring_ctx *ctx = data; struct mm_struct *cur_mm = NULL; + const struct cred *old_cred; mm_segment_t old_fs; DEFINE_WAIT(wait); unsigned inflight; @@ -1888,6 +1899,7 @@ static int io_sq_thread(void *data) old_fs = get_fs(); set_fs(USER_DS); + old_cred = override_creds(ctx->creds); timeout = inflight = 0; while (!kthread_should_stop() && !ctx->sqo_stop) { @@ -2001,6 +2013,7 @@ static int io_sq_thread(void *data) unuse_mm(cur_mm); mmput(cur_mm); } + revert_creds(old_cred); if (kthread_should_park()) kthread_parkme(); @@ -2645,6 +2658,8 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx) io_unaccount_mem(ctx->user, ring_pages(ctx->sq_entries, ctx->cq_entries)); free_uid(ctx->user); + if (ctx->creds) + put_cred(ctx->creds); kfree(ctx); } @@ -2924,6 +2939,12 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p) ctx->account_mem = account_mem; ctx->user = user; + ctx->creds = prepare_creds(); + if (!ctx->creds) { + ret = -ENOMEM; + goto err; + } + ret = io_allocate_scq_urings(ctx, p); if (ret) goto err; -- 2.24.0