From 3537b6a7c65434d0d2cc0c9862e69be11c367fdc Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 3 Apr 2020 11:19:06 -0600 Subject: 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 Signed-off-by: Jens Axboe --- fs/io_uring.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'fs/io_uring.c') diff --git a/fs/io_uring.c b/fs/io_uring.c index 8ad4a151994d..b343525a4d2e 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -615,10 +615,8 @@ struct io_kiocb { struct list_head list; unsigned int flags; refcount_t refs; - union { - struct task_struct *task; - unsigned long fsize; - }; + struct task_struct *task; + unsigned long fsize; u64 user_data; u32 result; u32 sequence; @@ -1336,6 +1334,7 @@ got_it: req->flags = 0; /* one is dropped after submission, the other at completion */ refcount_set(&req->refs, 2); + req->task = NULL; req->result = 0; INIT_IO_WORK(&req->work, io_wq_submit_work); return req; @@ -1372,6 +1371,8 @@ static void __io_req_aux_free(struct io_kiocb *req) kfree(req->io); if (req->file) io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE)); + if (req->task) + put_task_struct(req->task); io_req_work_drop_env(req); } @@ -4256,10 +4257,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req) req->flags |= REQ_F_POLLED; memcpy(&apoll->work, &req->work, sizeof(req->work)); - /* - * Don't need a reference here, as we're adding it to the task - * task_works list. If the task exits, the list is pruned. - */ + get_task_struct(current); req->task = current; req->apoll = apoll; 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 events = READ_ONCE(sqe->poll_events); poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP; - /* - * Don't need a reference here, as we're adding it to the task - * task_works list. If the task exits, the list is pruned. - */ + get_task_struct(current); req->task = current; return 0; } -- cgit v1.2.1