diff options
author | Jens Axboe <axboe@kernel.dk> | 2020-04-03 11:19:06 -0600 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2020-04-03 11:35:57 -0600 |
commit | 3537b6a7c65434d0d2cc0c9862e69be11c367fdc (patch) | |
tree | 8f3c4d985747b9c52e4eaef92254958da32b75a8 /fs/io_uring.c | |
parent | a6ba632d2c249a4390289727c07b8b55eb02a41d (diff) | |
download | linux-3537b6a7c65434d0d2cc0c9862e69be11c367fdc.tar.bz2 |
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 <dmm@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'fs/io_uring.c')
-rw-r--r-- | fs/io_uring.c | 19 |
1 files changed, 7 insertions, 12 deletions
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; } |