io_uring: sanitise ring params earlier
authorPavel Begunkov <asml.silence@gmail.com>
Fri, 31 Jan 2025 17:31:03 +0000 (17:31 +0000)
committerJens Axboe <axboe@kernel.dk>
Mon, 17 Feb 2025 12:34:45 +0000 (05:34 -0700)
Do all struct io_uring_params validation early on before allocating the
context. That makes initialisation easier, especially by having fewer
places where we need to care about partial de-initialisation.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/363ba90b83ff78eefdc88b60e1b2c4a39d182247.1738344646.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/io_uring.c

index 7fff5d612201b291353b5b1326dad8432c5edc8d..e34a92c73a5d8968aea9cd0c75dfa68cfe380649 100644 (file)
@@ -3535,6 +3535,44 @@ static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
                                         O_RDWR | O_CLOEXEC, NULL);
 }
 
+static int io_uring_sanitise_params(struct io_uring_params *p)
+{
+       unsigned flags = p->flags;
+
+       /* There is no way to mmap rings without a real fd */
+       if ((flags & IORING_SETUP_REGISTERED_FD_ONLY) &&
+           !(flags & IORING_SETUP_NO_MMAP))
+               return -EINVAL;
+
+       if (flags & IORING_SETUP_SQPOLL) {
+               /* IPI related flags don't make sense with SQPOLL */
+               if (flags & (IORING_SETUP_COOP_TASKRUN |
+                            IORING_SETUP_TASKRUN_FLAG |
+                            IORING_SETUP_DEFER_TASKRUN))
+                       return -EINVAL;
+       }
+
+       if (flags & IORING_SETUP_TASKRUN_FLAG) {
+               if (!(flags & (IORING_SETUP_COOP_TASKRUN |
+                              IORING_SETUP_DEFER_TASKRUN)))
+                       return -EINVAL;
+       }
+
+       /* HYBRID_IOPOLL only valid with IOPOLL */
+       if ((flags & IORING_SETUP_HYBRID_IOPOLL) && !(flags & IORING_SETUP_IOPOLL))
+               return -EINVAL;
+
+       /*
+        * For DEFER_TASKRUN we require the completion task to be the same as
+        * the submission task. This implies that there is only one submitter.
+        */
+       if ((flags & IORING_SETUP_DEFER_TASKRUN) &&
+           !(flags & IORING_SETUP_SINGLE_ISSUER))
+               return -EINVAL;
+
+       return 0;
+}
+
 int io_uring_fill_params(unsigned entries, struct io_uring_params *p)
 {
        if (!entries)
@@ -3545,10 +3583,6 @@ int io_uring_fill_params(unsigned entries, struct io_uring_params *p)
                entries = IORING_MAX_ENTRIES;
        }
 
-       if ((p->flags & IORING_SETUP_REGISTERED_FD_ONLY)
-           && !(p->flags & IORING_SETUP_NO_MMAP))
-               return -EINVAL;
-
        /*
         * Use twice as many entries for the CQ ring. It's possible for the
         * application to drive a higher depth than the size of the SQ ring,
@@ -3610,6 +3644,10 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
        struct file *file;
        int ret;
 
+       ret = io_uring_sanitise_params(p);
+       if (ret)
+               return ret;
+
        ret = io_uring_fill_params(entries, p);
        if (unlikely(ret))
                return ret;
@@ -3657,37 +3695,10 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
         * For SQPOLL, we just need a wakeup, always. For !SQPOLL, if
         * COOP_TASKRUN is set, then IPIs are never needed by the app.
         */
-       ret = -EINVAL;
-       if (ctx->flags & IORING_SETUP_SQPOLL) {
-               /* IPI related flags don't make sense with SQPOLL */
-               if (ctx->flags & (IORING_SETUP_COOP_TASKRUN |
-                                 IORING_SETUP_TASKRUN_FLAG |
-                                 IORING_SETUP_DEFER_TASKRUN))
-                       goto err;
+       if (ctx->flags & (IORING_SETUP_SQPOLL|IORING_SETUP_COOP_TASKRUN))
                ctx->notify_method = TWA_SIGNAL_NO_IPI;
-       } else if (ctx->flags & IORING_SETUP_COOP_TASKRUN) {
-               ctx->notify_method = TWA_SIGNAL_NO_IPI;
-       } else {
-               if (ctx->flags & IORING_SETUP_TASKRUN_FLAG &&
-                   !(ctx->flags & IORING_SETUP_DEFER_TASKRUN))
-                       goto err;
+       else
                ctx->notify_method = TWA_SIGNAL;
-       }
-
-       /* HYBRID_IOPOLL only valid with IOPOLL */
-       if ((ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_HYBRID_IOPOLL)) ==
-                       IORING_SETUP_HYBRID_IOPOLL)
-               goto err;
-
-       /*
-        * For DEFER_TASKRUN we require the completion task to be the same as the
-        * submission task. This implies that there is only one submitter, so enforce
-        * that.
-        */
-       if (ctx->flags & IORING_SETUP_DEFER_TASKRUN &&
-           !(ctx->flags & IORING_SETUP_SINGLE_ISSUER)) {
-               goto err;
-       }
 
        /*
         * This is just grabbed for accounting purposes. When a process exits,