Re: [PATCH] io_uring/kbuf: free the old cached iovec, not the returned one, on bundle grow

Gabriel Krisman Bertazi <[email protected]> Tue, 14 Jul 2026 10:02:11 -0400
Newsgroups org.kernel.vger.io-uring
Organization SUSE
Message-ID <[email protected]>
Doruk Tan Ozturk <[email protected]> writes:

> Commit cd053d788c3f ("io_uring: fix dangling iovec after provided-buffer
> bundle grow failure") moved the KBUF_MODE_FREE kfree() out of the expand
> branch to after the validation loop, so the old cached iovec is only
> released once the new buffers have been validated. However, by the time
> control reaches the post-loop free, arg->iovs has already been reassigned
> in the expand branch to the freshly allocated array that is about to be
> returned to the caller:
>
> 	iov = kmalloc_objs(struct iovec, nr_avail);
> 	...
> 	arg->iovs = iov;		/* now the array we return */
> 	...
> 	if (arg->mode & KBUF_MODE_FREE)
> 		kfree(arg->iovs);	/* ... but this frees it */
>
> On a successful grow, io_ring_buffers_peek() therefore frees the very
> iovec array it returns. io_recv_buf_select() then builds an iov_iter over
> that freed array and caches it in kmsg->vec.iovec, giving a
> slab-use-after-free read during the recv copy and a later double free of
> the iovec array on request cleanup. The array is a kmalloc() whose size is
> controlled by the number of ring buffers the caller commits, so the freed
> object lands in an attacker-influenced kmalloc cache.
>
> KBUF_MODE_FREE is meant to release the *old* cached iovec once it has been
> replaced by a larger one. Free the captured org_iovs instead, and only
> when a grow actually happened (arg->iovs != org_iovs) so the no-grow case
> still returns the reused array. The -EFAULT failure path already frees the
> new array and leaves org_iovs for the caller, so it is unaffected.
>
> Reproduced on next-20260710 with KASAN by an unprivileged IORING_OP_RECV
> using IORING_RECVSEND_BUNDLE over a provided-buffer ring: a first
> (expanding) bundle caches a small iovec, and an in-request bundle retry
> grows again under KBUF_MODE_FREE, triggering both the UAF read and the
> double free. The change eliminates the KASAN splat.
>
> Fixes: cd053d788c3f ("io_uring: fix dangling iovec after provided-buffer bundle grow failure")
> Signed-off-by: Doruk Tan Ozturk <[email protected]>

Already fixed here

https://lore.kernel.org/io-uring/[email protected]/T/#u

here:

https://lore.kernel.org/io-uring/OS3PR01MB8810F38D613E37FBD684DC4D83FB2@OS3PR01MB8810.jpnprd01.prod.outlook.com/T/#t

and here:

https://lore.kernel.org/io-uring/[email protected]/T/#u

Aren't LLMs fun?

-- 
Gabriel Krisman Bertazi