io_uring: explicitly catch any illegal async queue attempt io_uring-5.14-2021-07-24
authorJens Axboe <axboe@kernel.dk>
Fri, 23 Jul 2021 17:53:54 +0000 (11:53 -0600)
committerJens Axboe <axboe@kernel.dk>
Fri, 23 Jul 2021 22:44:51 +0000 (16:44 -0600)
Catch an illegal case to queue async from an unrelated task that got
the ring fd passed to it. This should not be possible to hit, but
better be proactive and catch it explicitly. io-wq is extended to
check for early IO_WQ_WORK_CANCEL being set on a work item as well,
so it can run the request through the normal cancelation path.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io-wq.c
fs/io_uring.c

index 843d4a7bcd6e94e1cdb0abbfa71a74211bee6046..cf086b01c6c675d0e9c8cbef88c1ef5df00c3fb6 100644 (file)
@@ -731,7 +731,12 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
        int work_flags;
        unsigned long flags;
 
-       if (test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state)) {
+       /*
+        * If io-wq is exiting for this task, or if the request has explicitly
+        * been marked as one that should not get executed, cancel it here.
+        */
+       if (test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state) ||
+           (work->flags & IO_WQ_WORK_CANCEL)) {
                io_run_cancel(work, wqe);
                return;
        }
index 117dc32eb8a8be5a7a626e722610efcf17b6e5d9..5a0fd6bcd3180a9b5ec470187522c765d676d10d 100644 (file)
@@ -1294,6 +1294,17 @@ static void io_queue_async_work(struct io_kiocb *req)
 
        /* init ->work of the whole link before punting */
        io_prep_async_link(req);
+
+       /*
+        * Not expected to happen, but if we do have a bug where this _can_
+        * happen, catch it here and ensure the request is marked as
+        * canceled. That will make io-wq go through the usual work cancel
+        * procedure rather than attempt to run this request (or create a new
+        * worker for it).
+        */
+       if (WARN_ON_ONCE(!same_thread_group(req->task, current)))
+               req->work.flags |= IO_WQ_WORK_CANCEL;
+
        trace_io_uring_queue_async_work(ctx, io_wq_is_hashed(&req->work), req,
                                        &req->work, req->flags);
        io_wq_enqueue(tctx->io_wq, &req->work);