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