From 55f4bb9373ca4a521f3b0119366db92715a39b81 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Jun 2026 15:06:23 +0100 Subject: iov_iter: Fix potential underflow in iov_iter_extract_xarray_pages() In iov_iter_extract_xarray_pages(), if no pages are extracted because there's a hole (or something otherwise unextractable) in the xarray, then the calculation of maxsize at the end can go wrong if the starting offset is not zero. Fix this by returning 0 in such a case and freeing the page array if allocated here rather than being passed in. Note that in the near future, ITER_XARRAY should be removed. Fixes: 7d58fe731028 ("iov_iter: Add a function to extract a page list from an iterator") Link: https://sashiko.dev/#/patchset/20260608145432.681865-1-dhowells%40redhat.com Link: https://sashiko.dev/#/patchset/20260616100821.2062304-1-dhowells%40redhat.com Signed-off-by: David Howells Link: https://patch.msgid.link/20260625140640.3116900-6-dhowells@redhat.com Reviewed-by: Christoph Hellwig cc: Paulo Alcantara cc: Matthew Wilcox cc: Christoph Hellwig cc: Jens Axboe cc: Mike Marshall cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- lib/iov_iter.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib') diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 273919b16161..0f320b4e82a8 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1568,6 +1568,7 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, struct folio *folio; unsigned int nr = 0, offset; loff_t pos = i->xarray_start + i->iov_offset; + bool will_alloc = !*pages; XA_STATE(xas, i->xarray, pos >> PAGE_SHIFT); offset = pos & ~PAGE_MASK; @@ -1595,6 +1596,14 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, } rcu_read_unlock(); + if (!nr) { + if (will_alloc) { + kvfree(*pages); + *pages = NULL; + } + return 0; + } + maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize); iov_iter_advance(i, maxsize); return maxsize; -- cgit v1.2.3 From 70531f4f3a143f81baf549da7f59a24a9f87a65c Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Jun 2026 15:06:24 +0100 Subject: iov_iter: Fix missing alloc fail check in iov_iter_extract_bvec_pages() Fix iov_iter_extract_bvec_pages() to check if want_pages_array() fails and, if so, return -ENOMEM appropriately. Fixes: e4e535bff2bc ("iov_iter: don't require contiguous pages in iov_iter_extract_bvec_pages") Link: https://sashiko.dev/#/patchset/20260608145432.681865-1-dhowells%40redhat.com Signed-off-by: David Howells Link: https://patch.msgid.link/20260625140640.3116900-7-dhowells@redhat.com Reviewed-by: Christoph Hellwig cc: Ming Lei cc: Paulo Alcantara cc: Matthew Wilcox cc: Christoph Hellwig cc: Jens Axboe cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- lib/iov_iter.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 0f320b4e82a8..3dfad70328eb 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1637,6 +1637,8 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i, bi.bi_bvec_done = skip; maxpages = want_pages_array(pages, maxsize, skip, maxpages); + if (!maxpages) + return -ENOMEM; while (bi.bi_size && bi.bi_idx < i->nr_segs) { struct bio_vec bv = bvec_iter_bvec(i->bvec, bi); -- cgit v1.2.3 From 72698020e15db16fc141e191b460bc335263b0ad Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Jun 2026 15:06:25 +0100 Subject: iov_iter: Fix a memory leak in iov_iter_extract_user_pages() There's a potential memory leak in callers of iov_iter_extract_user_pages() whereby if a pages array is allocated in function, it isn't freed before returning of an error or 0. Now, it's not a leak per se in iov_iter_extract_user_pages() as, if an array is allocated, it's returned through *pages, so it's incumbent on the caller to free it. However, not all callers do. Fix this by freeing the table and clearing *pages before returning an error or 0. Note that iov_iter_extract_pages() and its subfunctions are allowed to return 0 without returning an array (for instance if the iterator count is 0). Fixes: 7d58fe731028 ("iov_iter: Add a function to extract a page list from an iterator") Closes: https://sashiko.dev/#/patchset/20260616100821.2062304-1-dhowells%40redhat.com Signed-off-by: David Howells Link: https://patch.msgid.link/20260625140640.3116900-8-dhowells@redhat.com Reviewed-by: Christoph Hellwig cc: Paulo Alcantara cc: Matthew Wilcox cc: Christoph Hellwig cc: Jens Axboe cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- lib/iov_iter.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 3dfad70328eb..c2484551a4e8 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1756,6 +1756,7 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, unsigned long addr; unsigned int gup_flags = 0; size_t offset; + bool will_alloc = !*pages; int res; if (i->data_source == ITER_DEST) @@ -1772,8 +1773,14 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, if (!maxpages) return -ENOMEM; res = pin_user_pages_fast(addr, maxpages, gup_flags, *pages); - if (unlikely(res <= 0)) + if (unlikely(res <= 0)) { + if (will_alloc) { + kvfree(*pages); + *pages = NULL; + } return res; + } + maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - offset); iov_iter_advance(i, maxsize); return maxsize; -- cgit v1.2.3 From 0442e23a5f72c74ba18882e4a2eed305c687009d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Jun 2026 15:06:26 +0100 Subject: iov_iter: Remove unused variable in kunit_iov_iter.c Remove the no longer used variable 'b' from iov_kunit_copy_to_bvec(). The variable is initialised and incremented, but nothing now makes use of the value. Signed-off-by: David Howells Link: https://patch.msgid.link/20260625140640.3116900-9-dhowells@redhat.com Reviewed-by: Christoph Hellwig cc: Ming Lei cc: Paulo Alcantara cc: Matthew Wilcox cc: Christoph Hellwig cc: Jens Axboe cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- lib/tests/kunit_iov_iter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c index 1e6fce9cb255..d9690ba1db88 100644 --- a/lib/tests/kunit_iov_iter.c +++ b/lib/tests/kunit_iov_iter.c @@ -283,7 +283,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) struct page **spages, **bpages; u8 *scratch, *buffer; size_t bufsize, npages, size, copied; - int i, b, patt; + int i, patt; bufsize = 0x100000; npages = bufsize / PAGE_SIZE; @@ -306,10 +306,9 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) KUNIT_EXPECT_EQ(test, iter.nr_segs, 0); /* Build the expected image in the scratch buffer. */ - b = 0; patt = 0; memset(scratch, 0, bufsize); - for (pr = bvec_test_ranges; pr->from >= 0; pr++, b++) { + for (pr = bvec_test_ranges; pr->from >= 0; pr++) { u8 *p = scratch + pr->page * PAGE_SIZE; for (i = pr->from; i < pr->to; i++) -- cgit v1.2.3 From 2bcd3ab3728752425ff5ab1e4be1698eba13d0d8 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Jun 2026 15:06:27 +0100 Subject: scatterlist: Fix offset in folio calc in extract_xarray_to_sg() Fix the calculation of the offset in the folio being extracted in extract_xarray_to_sg(). Note that in the near future, ITER_XARRAY should be removed. Fixes: f5f82cd18732 ("Move netfs_extract_iter_to_sg() to lib/scatterlist.c") Link: https://sashiko.dev/#/patchset/20260608145432.681865-1-dhowells%40redhat.com Signed-off-by: David Howells Link: https://patch.msgid.link/20260625140640.3116900-10-dhowells@redhat.com Reviewed-by: Christoph Hellwig cc: Paulo Alcantara cc: Matthew Wilcox cc: Christoph Hellwig cc: Jens Axboe cc: Mike Marshall cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) --- lib/scatterlist.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/scatterlist.c b/lib/scatterlist.c index b7fe91ef35b8..6ea40d2e6247 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -1366,6 +1366,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter, sg_max--; maxsize -= len; + start += len; ret += len; if (maxsize <= 0 || sg_max == 0) break; -- cgit v1.2.3