From nobody Sun Apr 5 16:35:11 2026 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB8522ED17B for ; Tue, 24 Mar 2026 20:35:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384512; cv=none; b=UYJ55l27IlRW5WTz8fG+I1UX1PXOp3o8vEmw0ct34x0Ihkilm8hrqxc3A0t+PydemkY0XveNDqSg4aY9MAcO5xe0I6ggVA7fWB8izu4YFWEWlhvn6vd6xXqkJkhWKbDKBHgJL52gXjfntshp4fhHFT5nfmZXfuaWW3Cf1+apCeo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384512; c=relaxed/simple; bh=ClFjq4qysXJIYEcYDgHb639NolK9rw2GDJpagcruyCo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rMTKX8JJRbxpq6A+szoca+W+JF2VLH2bzIsrh4ipXsTSBt1M+dF0gk7DJ2xSSTsDFvHphbT9w+nx0m1/BCbvmPJBwBLt67Wfl6vzEQFPb1OrBYC0cYgU3a8ih0n4GtTHomy3MmeOZ78jr4DL41ovqKaFwRZa+XMfsTkwbSXB25k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 83BB9140060; Tue, 24 Mar 2026 21:35:08 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-kernel@vger.kernel.org, Andrew Morton , Josh Law , David Howells Cc: "Christian A. Ehrhardt" , Kees Cook , Petr Mladek , David Gow Subject: [PATCH v2 1/3] lib: kunit_iov_iter: Improve error detection Date: Tue, 24 Mar 2026 21:34:51 +0100 Message-Id: <20260324203453.810499-2-lk@c--e.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260324203453.810499-1-lk@c--e.de> References: <20260324203453.810499-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In the kunit_iov_iter test prevent the kernel buffer from being a single physically contiguous region. Additionally, make sure that the test pattern written to a page in the buffer depends on the offset of the page within the buffer. Cc: David Howells Cc: Andrew Morton Signed-off-by: Christian A. Ehrhardt Reviewed-by: Josh Law Tested-By: Josh Law --- lib/tests/kunit_iov_iter.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c index bb847e5010eb..c42b9235f57a 100644 --- a/lib/tests/kunit_iov_iter.c +++ b/lib/tests/kunit_iov_iter.c @@ -13,6 +13,7 @@ #include #include #include +#include #include =20 MODULE_DESCRIPTION("iov_iter testing"); @@ -37,7 +38,7 @@ static const struct kvec_test_range kvec_test_ranges[] = =3D { =20 static inline u8 pattern(unsigned long x) { - return x & 0xff; + return (u8)x + (u8)(x >> 8) + (u8)(x >> 16); } =20 static void iov_kunit_unmap(void *data) @@ -52,6 +53,7 @@ static void *__init iov_kunit_create_buffer(struct kunit = *test, struct page **pages; unsigned long got; void *buffer; + unsigned int i; =20 pages =3D kunit_kcalloc(test, npages, sizeof(struct page *), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages); @@ -62,6 +64,9 @@ static void *__init iov_kunit_create_buffer(struct kunit = *test, release_pages(pages, got); KUNIT_ASSERT_EQ(test, got, npages); } + /* Make sure that we don't get a physically contiguous buffer. */ + for (i =3D 0; i < npages / 4; ++i) + swap(pages[i], pages[i + npages/2]); =20 buffer =3D vmap(pages, npages, VM_MAP | VM_MAP_PUT_PAGES, PAGE_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer); --=20 2.43.0 From nobody Sun Apr 5 16:35:11 2026 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D5C63537D8 for ; Tue, 24 Mar 2026 20:35:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384512; cv=none; b=UrE5SIDWzqdVhFwecMmwUwvDmet6ILoEPffANNaTTOIbkXqlaRKdPD+rDFNMdrIHXpt2s1iAtv/zRZvsDIgFNduE6vvUNoBF1bXQ/JK3F2OEsv3U8gtKc/g4RXK4RGVO9crevuIKWgTD0lSTU2PI5X05brvwIFgA0QmSFVp5YKo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384512; c=relaxed/simple; bh=+U5McEdlYtIs5hrDQ7jbLluY3wpEUkmk26AkoqwBehU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AlQFgX8u5lO3tnYINsCzBIrJCcuk1bONbG+e8Q+wcaWoMYP8Wk/1DwZ4nYyOM4kBjy+WWFDXEXa20nYWwWSzkgQ2gXm+WFAYmt5/GhHHeP5PhcyqS3tbklBhfFo1awVOWO4pSlZibbQLl2U1KcsY1c3H3znSvm7vONZgz2SUrns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id 9339C14008B; Tue, 24 Mar 2026 21:35:08 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-kernel@vger.kernel.org, Andrew Morton , Josh Law , David Howells Cc: "Christian A. Ehrhardt" , Kees Cook , Petr Mladek , David Gow Subject: [PATCH v2 2/3] lib: Fix length calculations in extract_kvec_to_sg Date: Tue, 24 Mar 2026 21:34:52 +0100 Message-Id: <20260324203453.810499-3-lk@c--e.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260324203453.810499-1-lk@c--e.de> References: <20260324203453.810499-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When extracting from a kvec to a scatterlist, do not cross page boundaries. The required length is already calculated but not used as intended. Adjust the copied length if the loop runs out auf sglist entries. While there return immediately from extract_iter_to_sg if there are no sglist entries at all. The changes to the kunit_iov_iter.c in the next commit demonstrate that the patch is necessary. Cc: David Howells Cc: Andrew Morton Cc: stable@vger.kernel.org # v6.5+ Fixes: 018584697533 ("netfs: Add a function to extract an iterator into a s= catterlist") Signed-off-by: Christian A. Ehrhardt Reviewed-by: Josh Law Tested-By: Josh Law --- lib/scatterlist.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/scatterlist.c b/lib/scatterlist.c index d773720d11bf..befdc4b9c11d 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -1247,7 +1247,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *it= er, else page =3D virt_to_page((void *)kaddr); =20 - sg_set_page(sg, page, len, off); + sg_set_page(sg, page, seg, off); sgtable->nents++; sg++; sg_max--; @@ -1256,6 +1256,7 @@ static ssize_t extract_kvec_to_sg(struct iov_iter *it= er, kaddr +=3D PAGE_SIZE; off =3D 0; } while (len > 0 && sg_max > 0); + ret -=3D len; =20 if (maxsize <=3D 0 || sg_max =3D=3D 0) break; @@ -1409,7 +1410,7 @@ ssize_t extract_iter_to_sg(struct iov_iter *iter, siz= e_t maxsize, struct sg_table *sgtable, unsigned int sg_max, iov_iter_extraction_t extraction_flags) { - if (maxsize =3D=3D 0) + if (maxsize =3D=3D 0 || sg_max =3D=3D 0) return 0; =20 switch (iov_iter_type(iter)) { --=20 2.43.0 From nobody Sun Apr 5 16:35:11 2026 Received: from cae.in-ulm.de (cae.in-ulm.de [217.10.14.231]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 831213537ED for ; Tue, 24 Mar 2026 20:35:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.10.14.231 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384513; cv=none; b=CjEoc5T8SdaXSGBBXDtCcsByWptFIDucdyNFbfWHpMaYKqCgov2Ks4kL//hDDe3RRmL+NrccORnQk55ofVj3+6fTrqwSoUYf32/qCsB6kkyjic/gT2Ui8J+FePyZf6ZDbhS+tmrtVi+9S0sglZJpUzWPuIZ+dXVv1P59nMmaQQk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384513; c=relaxed/simple; bh=Lgr8QBL25HZTkTzfAc9UrDEfVNlYlXuQUL57xH9fSjk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=a7Pgkrm47OxBdWWIcIOio7uhhhGLNS8AI6fUpmaRV/CuLmrE8zFQ6YPo/aWOGRn+/eDaZRYFoTuTGFyJqE+k3vKs+7ATf6ijLGGqXR6JPcqq9/6N6CtYo6ceTE1VIFD45Cn1rmCF8rxVJZvHCKv0Dp1P4TVDs+4QZRcCChG4rJk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de; spf=pass smtp.mailfrom=c--e.de; arc=none smtp.client-ip=217.10.14.231 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=c--e.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=c--e.de Received: by cae.in-ulm.de (Postfix, from userid 1000) id A0FAB1400FB; Tue, 24 Mar 2026 21:35:08 +0100 (CET) From: "Christian A. Ehrhardt" To: linux-kernel@vger.kernel.org, Andrew Morton , Josh Law , David Howells Cc: "Christian A. Ehrhardt" , Kees Cook , Petr Mladek , David Gow Subject: [PATCH v2 3/3] lib: kunit_iov_iter: Add tests for extract_iter_to_sg Date: Tue, 24 Mar 2026 21:34:53 +0100 Message-Id: <20260324203453.810499-4-lk@c--e.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260324203453.810499-1-lk@c--e.de> References: <20260324203453.810499-1-lk@c--e.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add test cases that test extract_iter_to_sg. For each iterator type an iterator is loaded with a kernel buffer. The iterator is then extracted to a scatterlist with multiple calls to extract_iter_to_sg. The final scatterlist is copied into a scratch buffer. The test passes if the scratch buffer compares equal to the original buffer. The new tests demostrate bugs in extract_iter_to_sg for kvec iterators that are fixed by the previous commit. Cc: David Howells Cc: Andrew Morton Signed-off-by: Christian A. Ehrhardt Reviewed-by: Josh Law Tested-By: Josh Law --- lib/tests/kunit_iov_iter.c | 152 +++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c index c42b9235f57a..159f61c9a30f 100644 --- a/lib/tests/kunit_iov_iter.c +++ b/lib/tests/kunit_iov_iter.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include =20 @@ -1014,6 +1015,153 @@ static void __init iov_kunit_extract_pages_xarray(s= truct kunit *test) KUNIT_SUCCEED(test); } =20 +struct iov_kunit_iter_to_sg_data { + struct sg_table sgt; + u8 *buffer, *scratch; + struct page **pages; + size_t npages; +}; + +static void __init +iov_kunit_iter_to_sg_init(struct kunit *test, size_t bufsize, + struct iov_kunit_iter_to_sg_data *data) +{ + struct page **spages; + struct scatterlist *sg; + size_t i; + + data->npages =3D bufsize / PAGE_SIZE; + sg =3D kunit_kmalloc_array(test, data->npages, sizeof(*sg), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sg); + sg_init_table(sg, data->npages); + memset(&data->sgt, 0, sizeof(data->sgt)); + data->sgt.orig_nents =3D data->npages; + data->sgt.sgl =3D sg; + + data->buffer =3D iov_kunit_create_buffer(test, &data->pages, + data->npages); + data->scratch =3D iov_kunit_create_buffer(test, &spages, data->npages); + for (i =3D 0; i < bufsize; ++i) + data->buffer[i] =3D pattern(i); + memset(data->scratch, 0, bufsize); +} + +static void __init +iov_kunit_iter_to_sg_check(struct kunit *test, struct iov_iter *iter, + size_t bufsize, + struct iov_kunit_iter_to_sg_data *data) +{ + size_t i; + + i =3D extract_iter_to_sg(iter, bufsize, &data->sgt, 0, 0); + KUNIT_EXPECT_EQ(test, i, 0); + KUNIT_EXPECT_EQ(test, data->sgt.nents, 0); + + i =3D extract_iter_to_sg(iter, bufsize, &data->sgt, 1, 0); + KUNIT_EXPECT_LE(test, i, bufsize); + KUNIT_EXPECT_EQ(test, data->sgt.nents, 1); + + i +=3D extract_iter_to_sg(iter, bufsize - i, &data->sgt, + data->npages - data->sgt.nents, 0); + + KUNIT_EXPECT_EQ(test, i, bufsize); + KUNIT_EXPECT_LE(test, data->sgt.nents, data->npages); + sg_mark_end(&data->sgt.sgl[data->sgt.nents - 1]); + + + i =3D sg_copy_to_buffer(data->sgt.sgl, data->sgt.nents, + data->scratch, bufsize); + KUNIT_EXPECT_EQ(test, i, bufsize); + + for (i =3D 0; i < bufsize; ++i) { + KUNIT_EXPECT_EQ_MSG(test, data->buffer[i], data->scratch[i], + "at i=3D%zx", i); + if (data->buffer[i] !=3D data->scratch[i]) + break; + } + + KUNIT_EXPECT_EQ(test, i, bufsize); +} + +static void __init iov_kunit_iter_to_sg_kvec(struct kunit *test) +{ + struct iov_kunit_iter_to_sg_data data; + struct iov_iter iter; + struct kvec kvec; + size_t bufsize; + + bufsize =3D 0x100000; + iov_kunit_iter_to_sg_init(test, bufsize, &data); + + kvec.iov_base =3D data.buffer; + kvec.iov_len =3D bufsize; + iov_iter_kvec(&iter, READ, &kvec, 1, bufsize); + + iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data); +} + +static void __init iov_kunit_iter_to_sg_bvec(struct kunit *test) +{ + struct iov_kunit_iter_to_sg_data data; + struct page *p, *can_merge =3D NULL; + size_t i, k, bufsize; + struct bio_vec *bvec; + struct iov_iter iter; + + bufsize =3D 0x100000; + iov_kunit_iter_to_sg_init(test, bufsize, &data); + + bvec =3D kunit_kmalloc_array(test, data.npages, sizeof(*bvec), + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bvec); + k =3D 0; + for (i =3D 0; i < data.npages; ++i) { + p =3D data.pages[i]; + if (p =3D=3D can_merge) + bvec[k-1].bv_len +=3D PAGE_SIZE; + else + bvec_set_page(&bvec[k++], p, PAGE_SIZE, 0); + can_merge =3D p + 1; + } + iov_iter_bvec(&iter, READ, bvec, k, bufsize); + + iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data); +} + +static void __init iov_kunit_iter_to_sg_folioq(struct kunit *test) +{ + struct iov_kunit_iter_to_sg_data data; + struct folio_queue *folioq; + struct iov_iter iter; + size_t bufsize; + + bufsize =3D 0x100000; + iov_kunit_iter_to_sg_init(test, bufsize, &data); + + folioq =3D iov_kunit_create_folioq(test); + iov_kunit_load_folioq(test, &iter, READ, folioq, data.pages, + data.npages); + + iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data); +} + +static void __init iov_kunit_iter_to_sg_xarray(struct kunit *test) +{ + struct iov_kunit_iter_to_sg_data data; + struct xarray *xarray; + struct iov_iter iter; + size_t bufsize; + + bufsize =3D 0x100000; + iov_kunit_iter_to_sg_init(test, bufsize, &data); + + xarray =3D iov_kunit_create_xarray(test); + iov_kunit_load_xarray(test, &iter, READ, xarray, data.pages, + data.npages); + + iov_kunit_iter_to_sg_check(test, &iter, bufsize, &data); +} + static struct kunit_case __refdata iov_kunit_cases[] =3D { KUNIT_CASE(iov_kunit_copy_to_kvec), KUNIT_CASE(iov_kunit_copy_from_kvec), @@ -1027,6 +1175,10 @@ static struct kunit_case __refdata iov_kunit_cases[]= =3D { KUNIT_CASE(iov_kunit_extract_pages_bvec), KUNIT_CASE(iov_kunit_extract_pages_folioq), KUNIT_CASE(iov_kunit_extract_pages_xarray), + KUNIT_CASE(iov_kunit_iter_to_sg_kvec), + KUNIT_CASE(iov_kunit_iter_to_sg_bvec), + KUNIT_CASE(iov_kunit_iter_to_sg_folioq), + KUNIT_CASE(iov_kunit_iter_to_sg_xarray), {} }; =20 --=20 2.43.0