]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
io_uring/msg_ring: reject CQE32 flag pass-through to normal rings
authorMelbin K Mathew <mlbnkm1@gmail.com>
Wed, 1 Jul 2026 08:11:45 +0000 (10:11 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 1 Jul 2026 11:39:26 +0000 (05:39 -0600)
IORING_OP_MSG_RING with IORING_MSG_RING_FLAGS_PASS allows a sender to
pass completion flags through sqe->file_index. If the sender sets
IORING_CQE_F_32 in file_index, the target-side completion path treats it
as a 32b CQE and writes big_cqe[0] and big_cqe[1] into the CQ ring
regardless of whether the target ring was created with
IORING_SETUP_CQE32 or IORING_SETUP_CQE_MIXED.

On a normal 16b CQE ring, this writes 16 extra bytes (two u64 big_cqe
fields) into the next CQE slot in the ring buffer. As the receiving ring
doesn't understand 32b CQEs, this is incorrect and they should be
rejected.

Fixes: cbeb47a7b5f0 ("io_uring/msg_ring: Pass custom flags to the cqe")
Signed-off-by: Melbin K Mathew <mlbnkm1@gmail.com>
Link: https://patch.msgid.link/20260701081145.196730-1-mlbnkm1@gmail.com
[axboe: edit commit message]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/msg_ring.c

index 3ff9098573dbf49eb8ac7df8ca74347c8baa5188..3067c93439919a0efc3608e53a56c15d40dd8f39 100644 (file)
@@ -93,19 +93,38 @@ static void io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req,
        io_req_task_work_add_remote(req, IOU_F_TWQ_LAZY_WAKE);
 }
 
+static int io_msg_ring_cqe_flags(struct io_ring_ctx *target_ctx,
+                                const struct io_msg *msg, u32 *flags)
+{
+       *flags = 0;
+
+       if (!(msg->flags & IORING_MSG_RING_FLAGS_PASS))
+               return 0;
+
+       *flags = msg->cqe_flags;
+       if ((*flags & IORING_CQE_F_32) &&
+           !(target_ctx->flags & (IORING_SETUP_CQE32 |
+                                  IORING_SETUP_CQE_MIXED)))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int io_msg_data_remote(struct io_ring_ctx *target_ctx,
                              struct io_msg *msg)
 {
        struct io_kiocb *target;
-       u32 flags = 0;
+       u32 flags;
+       int ret;
 
-       target = kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO)  ;
+       ret = io_msg_ring_cqe_flags(target_ctx, msg, &flags);
+       if (ret)
+               return ret;
+
+       target = kmem_cache_alloc(req_cachep, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
        if (unlikely(!target))
                return -ENOMEM;
 
-       if (msg->flags & IORING_MSG_RING_FLAGS_PASS)
-               flags = msg->cqe_flags;
-
        io_msg_remote_post(target_ctx, target, msg->len, flags, msg->user_data);
        return 0;
 }
@@ -130,8 +149,9 @@ static int __io_msg_ring_data(struct io_ring_ctx *target_ctx,
        if (io_msg_need_remote(target_ctx))
                return io_msg_data_remote(target_ctx, msg);
 
-       if (msg->flags & IORING_MSG_RING_FLAGS_PASS)
-               flags = msg->cqe_flags;
+       ret = io_msg_ring_cqe_flags(target_ctx, msg, &flags);
+       if (ret)
+               return ret;
 
        ret = -EOVERFLOW;
        if (target_ctx->flags & IORING_SETUP_IOPOLL) {