All of lore.kernel.org
 help / color / mirror / Atom feed
From: zjamg <ndaugoing@gmail.com>
To: Song Liu <song@kernel.org>, Yu Kuai <yukuai@fygo.io>
Cc: Li Nan <magiclinan@didiglobal.com>, Xiao Ni <xiao@kernel.org>,
	NeilBrown <neil@brown.name>,
	linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org,
	zjamg <ndaugoing@gmail.com>
Subject: [PATCH 0/2] md: fix bblog_size-driven OOB read in md_write_metadata()
Date: Thu, 17 Sep 2026 16:38:18 +0800	[thread overview]
Message-ID: <20260917083820.57091-1-ndaugoing@gmail.com> (raw)

Hi,

This series fixes an out-of-bounds read in the md badblocks log (bblog)
write path. The on-disk bblog_size field is taken verbatim from the
member device superblock and used as the bio length in
md_write_metadata(), without any check against the size of the page that
actually backs the write.

This is a different issue from CVE-2026-89557, which fixed the
bblog_shift overflow. The bblog_size path is still unfixed.

Introduced by commit 2699b67223ac ("md: load/store badblock list from v1.x metadata").

Mechanism:

  super_1_load() reads sb->bblog_size (__le16) from the member device
  and stores it in rdev->badblocks.size via super_1_sync() (md.c:2316).
  md_update_sb() then calls

      md_write_metadata(mddev, rdev, rdev->badblocks.sector,
                        rdev->badblocks.size << 9, rdev->bb_page, 0);

  (md.c:2944-2948). bb->size is sector_t, so 0xFFFF << 9 = 33553920
  does not wrap. md_write_metadata() passes that length to
  __bio_add_page() with a single 4 KiB page:

      __bio_add_page(bio, page, size, 0)

  __bio_add_page() is the no-check variant: after a WARN_ON_ONCE() it
  unconditionally records bvec_set_page(page, size, offset) and bumps
  bi_size/bi_vcnt. bio_full()'s second clause is
  "bi_size > BIO_MAX_SIZE - len", with bi_size == 0 and
  BIO_MAX_SIZE == UINT_MAX, so it is false and not even the WARN fires.
  The 4 KiB page is recorded as a bvec with bv_len == 33553920.

Downstream bvec iteration (nth_page, bio_split_to_limits, etc.) then
reads past the end of the page, into whatever follows in the linear
map. KASAN reports slab-out-of-bounds or slab-use-after-free, and the
data is written to the attacker-controlled member device.

Reproducer (CONTROL/ATTACK, only bblog_size differs):

  CONTROL bblog_size = 8      -> 4096 bytes land, out-of-range stays
                                 at the fill pattern
  ATTACK  bblog_size = 0xFFFF -> 33553920 bytes land, KASAN reports
                                 slab-out-of-bounds in
                                 copy_folio_from_iter_atomic(), and
                                 ~33.5 MB of kernel memory is copied
                                 into the member device image

The harness creates the on-disk superblock by hand, attaches the loop
device, binds it to a new md array via sysfs, adds one bad block, and
then writes "writemostly" to the member state attribute to force an
md_update_sb(). Both runs share the same kernel, the same md module and
the same code path; the only difference is the bblog_size field in the
on-disk superblock.

Patch 1 adds an upper bound for bb->size in super_1_sync(), matching
the existing guard in super_1_load().

Patch 2 is a defensive check in md_write_metadata() itself, so that
any future caller that passes an oversized length is caught before the
bio is built. Only one of the two is strictly needed to fix the
immediate issue; I'm sending both because the checks cover different
layers.

I can send the harness and full dmesg logs if useful.

Thanks.


zjamg (2):
  md: fix bblog_size-driven OOB read in super_1_load() and
    super_1_sync()
  md: add defensive bounds check for bio in md_write_metadata()

 drivers/md/md.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

-- 
2.53.0


             reply	other threads:[~2026-09-17  8:38 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-17  8:38 zjamg [this message]
2026-09-17  8:38 ` [PATCH 1/2] md: fix bblog_size-driven OOB read in super_1_load() and super_1_sync() zjamg
2026-09-20 11:50   ` yu kuai
2026-09-22  4:45     ` Yuchao Zhang
2026-09-22  4:46     ` [PATCH v2] md: validate bblog_size when loading v1.x badblocks metadata Yuchao Zhang
2026-09-23 11:16       ` yu kuai
2026-09-17  8:38 ` [PATCH 2/2] md: add defensive bounds check for bio in md_write_metadata() zjamg
2026-09-23 11:22   ` yu kuai

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=20260917083820.57091-1-ndaugoing@gmail.com \
    --to=ndaugoing@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-raid@vger.kernel.org \
    --cc=magiclinan@didiglobal.com \
    --cc=neil@brown.name \
    --cc=song@kernel.org \
    --cc=xiao@kernel.org \
    --cc=yukuai@fygo.io \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.