* [PATCH io_uring] io_uring/msg_ring: reject CQE32 flag pass-through to normal rings
@ 2026-07-01 8:11 Melbin K Mathew
2026-07-01 11:42 ` Jens Axboe
0 siblings, 1 reply; 2+ messages in thread
From: Melbin K Mathew @ 2026-07-01 8:11 UTC (permalink / raw)
To: axboe; +Cc: io-uring, linux-kernel, Melbin K Mathew
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 32-byte 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 16-byte CQE ring, this writes 16 extra bytes (two u64
big_cqe fields) into the next CQE slot in the ring buffer. This was
confirmed by poisoning the adjacent slot with known values and observing
them being overwritten after the pass-through, while the CQ tail
advanced by only one slot.
Add a helper io_msg_ring_cqe_flags() that validates the flags before
they are forwarded, and use it in both the local and remote data paths.
Reject with -EINVAL when IORING_CQE_F_32 is passed to a ring that does
not support CQE32 or mixed CQE modes. In the remote path, this guard
runs before the target request allocation to avoid a leak on error.
Fixes: cbeb47a7b5f0 ("io_uring/msg_ring: Pass custom flags to the cqe")
Signed-off-by: Melbin K Mathew <mlbnkm1@gmail.com>
---
Notes:
Testing on Linux 7.2-rc1 with KASAN and UBSAN enabled:
Unpatched kernel: MSG_RING with IORING_MSG_RING_FLAGS_PASS and
IORING_CQE_F_32 posts CQE_F_32 to a normal target ring. Target CQ
tail advances by one while the adjacent unpublished CQ slot is
overwritten (confirmed by poisoning the adjacent slot with known
values and observing them zeroed after the pass-through).
Patched kernel: sender receives -EINVAL. Target CQ tail does not
advance. Adjacent poisoned slot remains intact.
git apply --check: OK
checkpatch --strict: 0 errors, 0 warnings, 0 checks
make W=1 io_uring/msg_ring.o: clean
io_uring/msg_ring.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/io_uring/msg_ring.c b/io_uring/msg_ring.c
index 3ff9098573..3067c93439 100644
--- a/io_uring/msg_ring.c
+++ b/io_uring/msg_ring.c
@@ -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) {
--
2.39.5
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH io_uring] io_uring/msg_ring: reject CQE32 flag pass-through to normal rings
2026-07-01 8:11 [PATCH io_uring] io_uring/msg_ring: reject CQE32 flag pass-through to normal rings Melbin K Mathew
@ 2026-07-01 11:42 ` Jens Axboe
0 siblings, 0 replies; 2+ messages in thread
From: Jens Axboe @ 2026-07-01 11:42 UTC (permalink / raw)
To: Melbin K Mathew; +Cc: io-uring, linux-kernel
On Wed, 01 Jul 2026 10:11:45 +0200, Melbin K Mathew wrote:
> 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 32-byte 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.
>
> [...]
Applied, thanks!
[1/1] io_uring/msg_ring: reject CQE32 flag pass-through to normal rings
commit: 15cd3ccf9b179f0f76948d0901be3b15028bc768
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-01 11:42 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 8:11 [PATCH io_uring] io_uring/msg_ring: reject CQE32 flag pass-through to normal rings Melbin K Mathew
2026-07-01 11:42 ` Jens Axboe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox