All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] io_uring/net: don't truncate the bundle segment length to int
@ 2026-07-29 15:15 Baul Lee
  2026-07-29 15:34 ` Gabriel Krisman Bertazi
  2026-07-29 15:39 ` Jens Axboe
  0 siblings, 2 replies; 3+ messages in thread
From: Baul Lee @ 2026-07-29 15:15 UTC (permalink / raw)
  To: io-uring, linux-kernel; +Cc: Jens Axboe, stable, Baul Lee

io_bundle_nbufs() works out how many buffers a short bundle transfer
consumed by walking the mapped iovec and subtracting each segment from the
transferred length:

	do {
		int this_len = min_t(int, iov[nbufs].iov_len, ret);

		nbufs++;
		ret -= this_len;
	} while (ret);

iov_len is a size_t while this_len is an int, so a segment longer than
INT_MAX comes out negative.  ret then grows instead of shrinking and the
loop keeps walking, reading past the end of the array it was handed.

The recv bundle path can hand it such a segment.  io_recv_buf_select()
folds sr->mshot_total_len into arg.max_len, and that field is unsigned and
taken straight from sqe->optlen:

	if (sr->flags & IORING_RECV_MSHOT_LIM)
		arg.max_len = min_not_zero(arg.max_len, sr->mshot_total_len);

With sqe->len left at 0 nothing else lowers it, so arg.max_len can be
0xffffffff.  io_ring_buffers_peek() clamps each buffer against that rather
than against INT_MAX and records an iov_len above INT_MAX; a short receive
over that bundle then enters the loop above.

An unprivileged multishot IORING_OP_RECV with IOSQE_BUFFER_SELECT and
IORING_RECVSEND_BUNDLE, a provided buffer ring registered with
IOU_PBUF_RING_INC holding two buffers, and two bytes of data is enough to
reach it.  The two-entry iovec is a 32-byte kmalloc:

  BUG: KASAN: slab-out-of-bounds in io_bundle_nbufs+0x114/0x1a8
  Read of size 8 at addr ffff0000d39a1b68 by task io_repro/165
  Call trace:
   io_bundle_nbufs+0x114/0x1a8
   io_recv_finish+0x138/0xa38
   io_recv+0x38c/0x1008
   io_issue_sqe+0xc4/0x155c
   io_submit_sqes+0x6d0/0x1fac
   __arm64_sys_io_uring_enter+0x30c/0x1180

  Allocated by task 165:
   __kmalloc_noprof+0x1b8/0x444
   io_ring_buffers_peek+0x57c/0xbb4
   io_buffers_peek+0x168/0x2a0
   io_recv+0x598/0x1008

  The buggy address is located 8 bytes to the right of
  allocated 32-byte region [ffff0000d39a1b40, ffff0000d39a1b60)

Count in size_t.  ret is positive by the time the loop runs, since the
function returns early for ret <= 0, so widening loses nothing; this_len
stays bounded by ret, and the mapped length is never less than ret, so the
walk ends inside the array.

Fixing it here rather than by capping arg.max_len keeps the accounting
correct for every caller and does not disturb buffer selection: an
arg.max_len of 0 is a distinct "not set yet" state that
io_ring_buffers_peek() tests before it applies its own INT_MAX default,
and pre-filling it changes which bundles get expanded.

Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>

Fixes: a05d1f625c7a ("io_uring/net: support bundles for send")
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
---
The sr->len path into this loop is already rejected in
io_{send,recv}msg_prep(); this one comes in through sqe->optlen instead,
which is unsigned and so never trips a negative-length check.

 io_uring/net.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/io_uring/net.c b/io_uring/net.c
index 00a7df803b99..e8a066f8a9e3 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -500,7 +500,7 @@ static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret)
 	/* short transfer, count segments */
 	nbufs = 0;
 	do {
-		int this_len = min_t(int, iov[nbufs].iov_len, ret);
+		size_t this_len = min_t(size_t, iov[nbufs].iov_len, ret);
 
 		nbufs++;
 		ret -= this_len;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] io_uring/net: don't truncate the bundle segment length to int
  2026-07-29 15:15 [PATCH] io_uring/net: don't truncate the bundle segment length to int Baul Lee
@ 2026-07-29 15:34 ` Gabriel Krisman Bertazi
  2026-07-29 15:39 ` Jens Axboe
  1 sibling, 0 replies; 3+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-07-29 15:34 UTC (permalink / raw)
  To: Baul Lee, io-uring, linux-kernel; +Cc: Jens Axboe, stable, Baul Lee

Baul Lee <baul.lee@xbow.com> writes:

> io_bundle_nbufs() works out how many buffers a short bundle transfer
> consumed by walking the mapped iovec and subtracting each segment from the
> transferred length:
>
> 	do {
> 		int this_len = min_t(int, iov[nbufs].iov_len, ret);
>
> 		nbufs++;
> 		ret -= this_len;
> 	} while (ret);
>
> iov_len is a size_t while this_len is an int, so a segment longer than
> INT_MAX comes out negative.  ret then grows instead of shrinking and the
> loop keeps walking, reading past the end of the array it was handed.
>
> The recv bundle path can hand it such a segment.  io_recv_buf_select()
> folds sr->mshot_total_len into arg.max_len, and that field is unsigned and
> taken straight from sqe->optlen:
>
> 	if (sr->flags & IORING_RECV_MSHOT_LIM)
> 		arg.max_len = min_not_zero(arg.max_len, sr->mshot_total_len);
>
> With sqe->len left at 0 nothing else lowers it, so arg.max_len can be
> 0xffffffff.  io_ring_buffers_peek() clamps each buffer against that rather
> than against INT_MAX and records an iov_len above INT_MAX; a short receive
> over that bundle then enters the loop above.
>
> An unprivileged multishot IORING_OP_RECV with IOSQE_BUFFER_SELECT and
> IORING_RECVSEND_BUNDLE, a provided buffer ring registered with
> IOU_PBUF_RING_INC holding two buffers, and two bytes of data is enough to
> reach it.  The two-entry iovec is a 32-byte kmalloc:
>
>   BUG: KASAN: slab-out-of-bounds in io_bundle_nbufs+0x114/0x1a8
>   Read of size 8 at addr ffff0000d39a1b68 by task io_repro/165
>   Call trace:
>    io_bundle_nbufs+0x114/0x1a8
>    io_recv_finish+0x138/0xa38
>    io_recv+0x38c/0x1008
>    io_issue_sqe+0xc4/0x155c
>    io_submit_sqes+0x6d0/0x1fac
>    __arm64_sys_io_uring_enter+0x30c/0x1180
>
>   Allocated by task 165:
>    __kmalloc_noprof+0x1b8/0x444
>    io_ring_buffers_peek+0x57c/0xbb4
>    io_buffers_peek+0x168/0x2a0
>    io_recv+0x598/0x1008
>
>   The buggy address is located 8 bytes to the right of
>   allocated 32-byte region [ffff0000d39a1b40, ffff0000d39a1b60)
>
> Count in size_t.  ret is positive by the time the loop runs, since the
> function returns early for ret <= 0, so widening loses nothing; this_len
> stays bounded by ret, and the mapped length is never less than ret, so the
> walk ends inside the array.
>
> Fixing it here rather than by capping arg.max_len keeps the accounting
> correct for every caller and does not disturb buffer selection: an
> arg.max_len of 0 is a distinct "not set yet" state that
> io_ring_buffers_peek() tests before it applies its own INT_MAX default,
> and pre-filling it changes which bundles get expanded.
>
> Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
>
> Fixes: a05d1f625c7a ("io_uring/net: support bundles for send")
> Cc: stable@vger.kernel.org
> Signed-off-by: Baul Lee <baul.lee@xbow.com>

Reviewed-by: Gabriel Krisman Bertazi <krisman@suse.de>

-- 
Gabriel Krisman Bertazi

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] io_uring/net: don't truncate the bundle segment length to int
  2026-07-29 15:15 [PATCH] io_uring/net: don't truncate the bundle segment length to int Baul Lee
  2026-07-29 15:34 ` Gabriel Krisman Bertazi
@ 2026-07-29 15:39 ` Jens Axboe
  1 sibling, 0 replies; 3+ messages in thread
From: Jens Axboe @ 2026-07-29 15:39 UTC (permalink / raw)
  To: Baul Lee, io-uring, linux-kernel; +Cc: stable

On 7/29/26 9:15 AM, Baul Lee wrote:
> io_bundle_nbufs() works out how many buffers a short bundle transfer
> consumed by walking the mapped iovec and subtracting each segment from the
> transferred length:

Should already be fixed by:

https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git/commit/?h=io_uring-7.2&id=bc6d516abfe7085bf706aff22127859f06174f75

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-29 15:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 15:15 [PATCH] io_uring/net: don't truncate the bundle segment length to int Baul Lee
2026-07-29 15:34 ` Gabriel Krisman Bertazi
2026-07-29 15:39 ` Jens Axboe

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.