From: sashiko-bot@kernel.org
To: "Ran Hongyun" <ranhongyun1@huawei.com>,
agk@redhat.com, snitzer@kernel.org, mpatocka@redhat.com,
bmarzins@redhat.com, song@kernel.org, yukuai@fygo.io
Cc: dm-devel@lists.linux.dev, linux-raid@vger.kernel.org,
chengzhihao1@huawei.com, yangerkun@huawei.com,
yi.zhang@huawei.com
Subject: Re: [PATCH] md: validate raid_disks range before loading personality
Date: Mon, 09 Nov 2026 03:21:48 +0000 [thread overview]
Message-ID: <sashiko-outbox-204370@kernel.org> (raw)
In-Reply-To: <20261109025621.2031722-1-ranhongyun1@huawei.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] md: md_run() cap at MAX_RAID_DEVICES breaks valid arrays with >
253 disks
- [Medium] md: unchecked delta_disks in md_run() allows OOM warn and
divide-by-zero
- [Medium] md: missing raid_disks upper bound in update_raid_disks() on
online reshape
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [Medium] md/raid1: missing raid_disks upper bounds check in
raid1_reshape() [1]
--
commit fc41ec678e6b01e865c547317a0225da7de795ee
Author: Ran Hongyun <ranhongyun1@huawei.com>
md: validate raid_disks range before loading personality
This commit moves MAX_RAID_DEVICES (253) from dm-raid.c to md.h and rejects
mddev->raid_disks values outside [1, MAX_RAID_DEVICES] in md_run() before
invoking the personality run callback.
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 03e35386a8028..7b202b483e98c 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -6703,6 +6703,13 @@ int md_run(struct mddev *mddev)
> return -EINVAL;
> }
>
> + if (mddev->raid_disks <= 0 ||
> + mddev->raid_disks > MAX_RAID_DEVICES) {
> + pr_warn("md: %s: raid_disks %d out of range [1, %d]\n",
> + mdname(mddev), mddev->raid_disks, MAX_RAID_DEVICES);
> + return -EINVAL;
> + }
> +
> if (mddev->level != LEVEL_NONE)
> request_module("md-level-%d", mddev->level);
> else if (mddev->clevel[0])
[Severity: High]
Does capping mddev->raid_disks at MAX_RAID_DEVICES (253) in md_run() break
assembling valid native MD arrays with more than 253 member devices?
MAX_RAID_DEVICES was a dm-raid target limit, whereas native MD v1.x
superblocks support up to 384 devices in a 1 KiB superblock and up to 1920
devices in a 4 KiB superblock:
drivers/md/md.c:super_1_validate() {
...
mddev->max_disks = (4096-256)/2;
...
}
In addition, raid6_takeover() converts a 253-disk RAID5 array into a
254-disk RAID6 array by incrementing mddev->raid_disks to 254, which
md_run() will now refuse to assemble with -EINVAL.
[Severity: Medium]
When an array is started with an active reshape (mddev->reshape_position !=
MaxSector), can an unvalidated mddev->delta_disks bypass this check and
still trigger the oversized allocations or a divide-by-zero?
On an inactive array, writing a large value to sysfs raid_disks, setting
reshape_position, and then writing a small valid value to raid_disks (or
loading a superblock with a crafted delta_disks) leaves mddev->raid_disks
within [1, MAX_RAID_DEVICES] while mddev->delta_disks is arbitrarily
negative. raid5 setup_conf() and raid10 setup_conf() size their disk
allocations from mddev->raid_disks - mddev->delta_disks:
drivers/md/raid10.c:setup_conf() {
...
conf->mirrors = kzalloc_objs(struct raid10_info,
mddev->raid_disks + max(0, -mddev->delta_disks));
...
}
This still hits the MAX_PAGE_ORDER warning (and overflows a signed int if
mddev->delta_disks == INT_MIN). Furthermore, if mddev->delta_disks equals
mddev->raid_disks, conf->prev.raid_disks (mddev->raid_disks -
mddev->delta_disks) becomes 0 and raid10_run() -> enough() -> _enough()
divides by zero at (this + 1) % disks.
Checking that mddev->raid_disks - mddev->delta_disks is also within the
valid range when mddev->reshape_position != MaxSector would close this gap.
[Severity: Medium]
Does online reshape via update_raid_disks() bypass md_run() and leave
raid1, raid5, and raid10 exposed to the same unbounded allocations?
When reshaping an already-running array via sysfs raid_disks or
ioctl(SET_ARRAY_INFO), raid_disks_store() and update_array_info() call
update_raid_disks() directly without going through md_run():
drivers/md/md.c:update_raid_disks() {
...
if (raid_disks <= 0 ||
(mddev->max_disks && raid_disks >= mddev->max_disks))
return -EINVAL;
...
mddev->delta_disks = raid_disks - mddev->raid_disks;
...
rv = mddev->pers->check_reshape(mddev);
...
}
When mddev->max_disks is 0 (such as on non-persistent or external-metadata
arrays), any positive raid_disks up to INT_MAX is accepted and passed to
pers->check_reshape(), hitting the MAX_PAGE_ORDER and INT_MAX allocation
warnings in raid1_reshape(), raid10_check_reshape(), and raid5
check_reshape().
[Severity: Medium]
This problem wasn't introduced by this patch, but raid1_reshape() [1]
lacks an upper bounds check on raid_disks when reshaping a running array
with mddev->max_disks == 0:
drivers/md/raid1.c:raid1_reshape() {
...
raid_disks = mddev->raid_disks + mddev->delta_disks;
...
new_r1bio_size = offsetof(struct r1bio, bios[raid_disks * 2]);
newpool = mempool_create_kmalloc_pool(NR_RAID_BIOS, new_r1bio_size);
if (!newpool) {
return -ENOMEM;
}
newmirrors = kzalloc(array3_size(sizeof(struct raid1_info),
raid_disks, 2),
GFP_KERNEL);
...
}
Because update_raid_disks() does not bound raid_disks when mddev->max_disks
is 0, a large raid_disks value overflows raid_disks * 2 in signed 32-bit
arithmetic or exceeds KMALLOC_MAX_SIZE in mempool_create_kmalloc_pool() and
kzalloc(), triggering a slab warning in ___kmalloc_large_node().
[1] https://sashiko.dev/#/bug/linux-9d642fe4-31fe-4998-ac3d-c07a30507ae7
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109025621.2031722-1-ranhongyun1@huawei.com?part=1
prev parent reply other threads:[~2026-11-09 3:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 2:56 [PATCH] md: validate raid_disks range before loading personality Ran Hongyun
2026-11-09 3:21 ` sashiko-bot [this message]
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=sashiko-outbox-204370@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=agk@redhat.com \
--cc=bmarzins@redhat.com \
--cc=chengzhihao1@huawei.com \
--cc=dm-devel@lists.linux.dev \
--cc=linux-raid@vger.kernel.org \
--cc=mpatocka@redhat.com \
--cc=ranhongyun1@huawei.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=snitzer@kernel.org \
--cc=song@kernel.org \
--cc=yangerkun@huawei.com \
--cc=yi.zhang@huawei.com \
--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.