io_uring: fix multishot accept request leaks
authorPavel Begunkov <asml.silence@gmail.com>
Thu, 17 Nov 2022 18:40:16 +0000 (18:40 +0000)
committerJens Axboe <axboe@kernel.dk>
Thu, 17 Nov 2022 19:33:33 +0000 (12:33 -0700)
Having REQ_F_POLLED set doesn't guarantee that the request is
executed as a multishot from the polling path. Fortunately for us, if
the code thinks it's multishot issue when it's not, it can only ask to
skip completion so leaking the request. Use issue_flags to mark
multipoll issues.

Cc: stable@vger.kernel.org
Fixes: 390ed29b5e425 ("io_uring: add IORING_ACCEPT_MULTISHOT for accept")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/7700ac57653f2823e30b34dc74da68678c0c5f13.1668710222.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
include/linux/io_uring.h
io_uring/io_uring.c
io_uring/io_uring.h
io_uring/net.c

index 43bc8a2edccf5aa347142fb05029a49241d2b97c..0ded9e271523fa08a8749cc1d3f5810dcfd22549 100644 (file)
@@ -16,6 +16,9 @@ enum io_uring_cmd_flags {
        IO_URING_F_SQE128               = 4,
        IO_URING_F_CQE32                = 8,
        IO_URING_F_IOPOLL               = 16,
+
+       /* the request is executed from poll, it should not be freed */
+       IO_URING_F_MULTISHOT            = 32,
 };
 
 struct io_uring_cmd {
index 4a1e482747cc50f54cde14a9947917b80928af14..8840cf3e20f2c622a345952aaa24716654fd579d 100644 (file)
@@ -1768,7 +1768,7 @@ int io_poll_issue(struct io_kiocb *req, bool *locked)
        io_tw_lock(req->ctx, locked);
        if (unlikely(req->task->flags & PF_EXITING))
                return -EFAULT;
-       return io_issue_sqe(req, IO_URING_F_NONBLOCK);
+       return io_issue_sqe(req, IO_URING_F_NONBLOCK|IO_URING_F_MULTISHOT);
 }
 
 struct io_wq_work *io_wq_free_work(struct io_wq_work *work)
index e99a79f2df9b18365559d6623133f77fdb60e3a6..cef5ff924e6357e7493489928d020302706d9177 100644 (file)
@@ -17,8 +17,8 @@ enum {
        IOU_ISSUE_SKIP_COMPLETE = -EIOCBQUEUED,
 
        /*
-        * Intended only when both REQ_F_POLLED and REQ_F_APOLL_MULTISHOT
-        * are set to indicate to the poll runner that multishot should be
+        * Intended only when both IO_URING_F_MULTISHOT is passed
+        * to indicate to the poll runner that multishot should be
         * removed and the result is set on req->cqe.res.
         */
        IOU_STOP_MULTISHOT      = -ECANCELED,
index 15dea91625e21d58d902d3be7c2a1dc188e30cc2..a390d3ea486c3100908b8db9789a637e535f794c 100644 (file)
@@ -1289,8 +1289,7 @@ retry:
                         * return EAGAIN to arm the poll infra since it
                         * has already been done
                         */
-                       if ((req->flags & IO_APOLL_MULTI_POLLED) ==
-                           IO_APOLL_MULTI_POLLED)
+                       if (issue_flags & IO_URING_F_MULTISHOT)
                                ret = IOU_ISSUE_SKIP_COMPLETE;
                        return ret;
                }
@@ -1315,9 +1314,7 @@ retry:
                goto retry;
 
        io_req_set_res(req, ret, 0);
-       if (req->flags & REQ_F_POLLED)
-               return IOU_STOP_MULTISHOT;
-       return IOU_OK;
+       return (issue_flags & IO_URING_F_MULTISHOT) ? IOU_STOP_MULTISHOT : IOU_OK;
 }
 
 int io_socket_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)