block/blk-map.c | 2 ++ 1 file changed, 2 insertions(+)
In bio_map_user_iov(), when iov_iter_extract_pages() is called with pages
set to NULL (because nr_vecs > UIO_FASTIOV), want_pages_array() internally
allocates a pages array via kvmalloc_array(). If iov_iter_extract_pages()
subsequently returns bytes <= 0 (e.g., due to pin_user_pages_fast()
failure), the code jumps to out_unmap without freeing the dynamically
allocated pages array, causing a memory leak detectable by kmemleak.
This can be triggered from userspace by issuing an SG_IO v4 ioctl on a
bsg device with a large din_xfer_len and an invalid din_xferp (mapped
PROT_NONE), which causes pin_user_pages_fast() to fail after the pages
array has already been allocated by want_pages_array().
The kmemleak backtrace looks like:
unreferenced object 0xffff... (size 2048):
backtrace (crc 0):
kvmalloc_node+0x...
want_pages_array+0x...
iov_iter_extract_pages+0x...
bio_map_user_iov+0x...
blk_rq_map_user_iov+0x...
blk_rq_map_user+0x...
bsg_transport_sg_io_fn+0x...
Fix this by freeing the dynamically allocated pages array (when it
differs from the on-stack stack_pages) before jumping to the error path.
Fixes: 403b6fb8dac1 ("block: convert bio_map_user_iov to use iov_iter_extract_pages")
Cc: stable@vger.kernel.org # 6.5+
Signed-off-by: Xin Yin <yinxin.x@bytedance.com>
---
block/blk-map.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/blk-map.c b/block/blk-map.c
index 0aadbaf7a9ddd..5b9f14caad4f9 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -304,6 +304,8 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
bytes = iov_iter_extract_pages(iter, &pages, LONG_MAX,
nr_vecs, extraction_flags, &offs);
if (unlikely(bytes <= 0)) {
+ if (pages != stack_pages)
+ kvfree(pages);
ret = bytes ? bytes : -EFAULT;
goto out_unmap;
}
--
2.20.1
> From: "Xin Yin"<yinxin.x@bytedance.com>
> Date: Sat, May 9, 2026, 12:23
> Subject: [PATCH] block: fix pages array leak in bio_map_user_iov error path
> To: <axboe@kernel.dk>, <dhowells@redhat.com>
> Cc: <linux-block@vger.kernel.org>, <linux-kernel@vger.kernel.org>, "Xin Yin"<yinxin.x@bytedance.com>, <stable@vger.kernel.org>
> In bio_map_user_iov(), when iov_iter_extract_pages() is called with pages
> set to NULL (because nr_vecs > UIO_FASTIOV), want_pages_array() internally
> allocates a pages array via kvmalloc_array(). If iov_iter_extract_pages()
> subsequently returns bytes <= 0 (e.g., due to pin_user_pages_fast()
> failure), the code jumps to out_unmap without freeing the dynamically
> allocated pages array, causing a memory leak detectable by kmemleak.
>
> This can be triggered from userspace by issuing an SG_IO v4 ioctl on a
> bsg device with a large din_xfer_len and an invalid din_xferp (mapped
> PROT_NONE), which causes pin_user_pages_fast() to fail after the pages
> array has already been allocated by want_pages_array().
>
> The kmemleak backtrace looks like:
>
> unreferenced object 0xffff... (size 2048):
> backtrace (crc 0):
> kvmalloc_node+0x...
> want_pages_array+0x...
> iov_iter_extract_pages+0x...
> bio_map_user_iov+0x...
> blk_rq_map_user_iov+0x...
> blk_rq_map_user+0x...
> bsg_transport_sg_io_fn+0x...
>
> Fix this by freeing the dynamically allocated pages array (when it
> differs from the on-stack stack_pages) before jumping to the error path.
>
> Fixes: 403b6fb8dac1 ("block: convert bio_map_user_iov to use iov_iter_extract_pages")
> Cc: stable@vger.kernel.org # 6.5+
> Signed-off-by: Xin Yin <yinxin.x@bytedance.com>
> ---
> block/blk-map.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/block/blk-map.c b/block/blk-map.c
> index 0aadbaf7a9ddd..5b9f14caad4f9 100644
> --- a/block/blk-map.c
> +++ b/block/blk-map.c
> @@ -304,6 +304,8 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
> bytes = iov_iter_extract_pages(iter, &pages, LONG_MAX,
> nr_vecs, extraction_flags, &offs);
> if (unlikely(bytes <= 0)) {
> + if (pages != stack_pages)
> + kvfree(pages);
> ret = bytes ? bytes : -EFAULT;
> goto out_unmap;
> }
> --
> 2.20.1
>
Hi Jens
Gentle ping on this patch.
This patch fixes a memory leak in bio_map_user_iov() that only affects
stable kernels (6.5+) carrying commit 403b6fb8dac1. Mainline resolved
this through a later refactoring that removed the affected code path
entirely, so there is no upstream commit to backport.
Could this be picked up for 6.6.y?
Thanks,
Xin Yin
© 2016 - 2026 Red Hat, Inc.