mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Charles Pellegrini <c4ffein.work@gmail.com>
To: akpm@linux-foundation.org, egorenar-dev@posteo.net,
	robert.jarzmik@free.fr, t-pratham@ti.com, david@davidgow.net,
	linux-kernel@vger.kernel.org
Subject: [PATCH v2 0/5] lib: scatterlist: fix sg_split() partial-coverage geometry, two latent corruption bugs, and add KUnit tests
Date: Wed, 10 Jun 2026 15:39:32 -0700 (PDT)	[thread overview]
Message-ID: <178113124323.90620.6403136846887207198@gmail.com> (raw)
In-Reply-To: <178027099087.72481.1976843064458686851@gmail.com>

v1 was a 2-patch series (the overshoot fix + a KUnit suite). Andrew's
review asked whether this was seen in real life -- it was not; it came
from property-based testing, not a field report -- and pointed at an
automated review (Sashiko) that flagged a pre-existing OOB and a bug in
the test. Chasing those turned up a third, separate latent bug. v2
addresses all of it.

sg_split() is EXPORT_SYMBOL'd, so its contract is "any caller, any
split_sizes[]", not just the six in-tree call sites. None of the three
bugs below is triggered by an in-tree caller today -- all are latent. So
even without a real-world trigger, I think they're worth fixing.

The three bugs (all Fixes: f8bcbe62acd0):

1. sg_calculate_split() nb_splits overshoot (the v1 fix, unchanged).
   Partial coverage ending mid-entry of a non-last input entry overshoots
   the counter to -1, misses the !nb_splits termination check, and folds a
   trailing entry into the last split.

2. sg_split_phys() ->length clobber. On !NEED_SG_DMA_LENGTH arches
   sg_dma_len() aliases ->length, so the DMA-scrub line zeroes the CPU
   length it has just computed; only the last entry is restored, so the
   non-last entries of a multi-entry split keep length 0 -> silent short
   data. Found while correcting the test argument below.

3. zero-nents ZERO_SIZE_PTR OOB. A trailing zero-size split that receives
   no input entry leaves out_sg == ZERO_SIZE_PTR; the out_sg[-1].length
   write is then out-of-bounds (KASAN splat). Flagged by the automated
   review; confirmed with KASAN and a userspace ASAN harness.

Plus a test-argument fix folded into the suite: v1 passed in_mapped_nents
= n_in for an unmapped list, where it must be 0. On NEED arches that drove
the mapped pass to read a zeroed dma_length and return -EINVAL, so the
suite would fail there (it passed on UML only because UML aliases dma_len
onto ->length). Correcting it is what exposed bug 2.

Patch layout (bisect-safe):

  1/5  overshoot fix              -- unchanged from v1
  2/5  ->length clobber fix       -- bug 2; lands before the test that
                                     exposes it
  3/5  KUnit suite                -- corrected in_mapped_nents; each case
                                     run unmapped AND identity-mapped;
                                     DMA-address + end-marker assertions;
                                     NEED-gated divergent-geometry cases
  4/5  zero-nents OOB guard       -- bug 3
  5/5  zero-nents regression test -- guards 4/5

Patches 4 and 5 are an isolable tail: if you'd rather treat a malformed
zero-size split as the caller's problem, they drop cleanly without
touching 1-3. On that bug I went tolerate-and-skip rather than rejecting
with -EINVAL, reasoning it's the droppable tail of the request -- trivial
to respin to -EINVAL if you prefer the stricter contract.

Testing. The suite runs each case both unmapped and identity-mapped
(dma_len == length, contiguous IOVA) on all arches, plus NEED-gated
divergent CPU/DMA geometry (coalescing) cases exercised on x86_64 with
KASAN. Results: UML (!NEED) 17 passed / 3 skipped; x86_64 + KASAN 20/20.
With bug 2 reverted, six unmapped multi-entry cases fail while their
mapped variants pass, so the suite catches it. A real dma_map_sg / IOMMU
rig is still deferred; the mapped coverage here is synthetic (identity
mapping + injected coalescing).

v1: https://lore.kernel.org/all/178027099087.72481.1976843064458686851@gmail.com/

Changes since v1:
 - corrected the KUnit in_mapped_nents argument (0 for unmapped lists)
 - new: sg_split_phys() ->length clobber fix (bug 2)
 - new: zero-nents OOB guard + its regression test (bug 3)
 - tests now run unmapped AND identity-mapped, with DMA-address and
   end-marker assertions and NEED-gated divergent-geometry cases
 - test file moved to lib/tests/sg_split_kunit.c (modern location);
   config moved to lib/Kconfig.debug, Makefile line to lib/tests/Makefile

Charles Pellegrini (5):
  lib: scatterlist: fix sg_calculate_split() nb_splits overshoot on
    partial coverage
  lib: scatterlist: fix sg_split_phys() ->length clobber on
    !NEED_SG_DMA_LENGTH
  lib: scatterlist: add KUnit tests for sg_split()
  lib: scatterlist: guard sg_split_phys()/sg_split_mapped() against
    zero-nents splits
  lib: scatterlist: add zero-nents regression test for sg_split()

 lib/Kconfig.debug          |  14 +
 lib/sg_split.c             |  15 +-
 lib/tests/Makefile         |   1 +
 lib/tests/sg_split_kunit.c | 526 +++++++++++++++++++++++++++++++++++++
 4 files changed, 552 insertions(+), 4 deletions(-)
 create mode 100644 lib/tests/sg_split_kunit.c

-- 
2.47.3


  parent reply	other threads:[~2026-06-10 22:39 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-31 23:42 [PATCH 0/2] lib: scatterlist: fix sg_split() partial-coverage geometry + " Charles Pellegrini
2026-05-31 23:42 ` [PATCH 1/2] lib: scatterlist: fix sg_calculate_split() nb_splits overshoot on partial coverage Charles Pellegrini
2026-05-31 23:42 ` [PATCH 2/2] lib: scatterlist: add KUnit tests for sg_split() Charles Pellegrini
2026-06-02  0:55 ` [PATCH 0/2] lib: scatterlist: fix sg_split() partial-coverage geometry + add KUnit tests Andrew Morton
2026-06-10 22:35   ` c4ffein.work
2026-06-10 22:39 ` Charles Pellegrini [this message]
2026-06-10 22:39   ` [PATCH v2 2/5] lib: scatterlist: fix sg_split_phys() ->length clobber on !NEED_SG_DMA_LENGTH Charles Pellegrini
2026-06-10 22:39   ` [PATCH v2 1/5] lib: scatterlist: fix sg_calculate_split() nb_splits overshoot on partial coverage Charles Pellegrini
2026-06-10 22:39   ` [PATCH v2 3/5] lib: scatterlist: add KUnit tests for sg_split() Charles Pellegrini
2026-06-10 22:39   ` [PATCH v2 4/5] lib: scatterlist: guard sg_split_phys()/sg_split_mapped() against zero-nents splits Charles Pellegrini
2026-06-10 22:39   ` [PATCH v2 5/5] lib: scatterlist: add zero-nents regression test for sg_split() Charles Pellegrini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178113124323.90620.6403136846887207198@gmail.com \
    --to=c4ffein.work@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=david@davidgow.net \
    --cc=egorenar-dev@posteo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robert.jarzmik@free.fr \
    --cc=t-pratham@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome