Skip to content

Commit 3537b6a

Browse files
committed
io_uring: grab task reference for poll requests
We can have a task exit if it's not the owner of the ring. Be safe and grab an actual reference to it, to avoid a potential use-after-free. Reported-by: Dan Melnic <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent a6ba632 commit 3537b6a

File tree

1 file changed

+7
-12
lines changed

1 file changed

+7
-12
lines changed

fs/io_uring.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -615,10 +615,8 @@ struct io_kiocb {
615615
struct list_head list;
616616
unsigned int flags;
617617
refcount_t refs;
618-
union {
619-
struct task_struct *task;
620-
unsigned long fsize;
621-
};
618+
struct task_struct *task;
619+
unsigned long fsize;
622620
u64 user_data;
623621
u32 result;
624622
u32 sequence;
@@ -1336,6 +1334,7 @@ static struct io_kiocb *io_get_req(struct io_ring_ctx *ctx,
13361334
req->flags = 0;
13371335
/* one is dropped after submission, the other at completion */
13381336
refcount_set(&req->refs, 2);
1337+
req->task = NULL;
13391338
req->result = 0;
13401339
INIT_IO_WORK(&req->work, io_wq_submit_work);
13411340
return req;
@@ -1372,6 +1371,8 @@ static void __io_req_aux_free(struct io_kiocb *req)
13721371
kfree(req->io);
13731372
if (req->file)
13741373
io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
1374+
if (req->task)
1375+
put_task_struct(req->task);
13751376

13761377
io_req_work_drop_env(req);
13771378
}
@@ -4256,10 +4257,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req)
42564257
req->flags |= REQ_F_POLLED;
42574258
memcpy(&apoll->work, &req->work, sizeof(req->work));
42584259

4259-
/*
4260-
* Don't need a reference here, as we're adding it to the task
4261-
* task_works list. If the task exits, the list is pruned.
4262-
*/
4260+
get_task_struct(current);
42634261
req->task = current;
42644262
req->apoll = apoll;
42654263
INIT_HLIST_NODE(&req->hash_node);
@@ -4482,10 +4480,7 @@ static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
44824480
events = READ_ONCE(sqe->poll_events);
44834481
poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP;
44844482

4485-
/*
4486-
* Don't need a reference here, as we're adding it to the task
4487-
* task_works list. If the task exits, the list is pruned.
4488-
*/
4483+
get_task_struct(current);
44894484
req->task = current;
44904485
return 0;
44914486
}

0 commit comments

Comments
 (0)