From: sashiko-bot@kernel.org
To: "Abd-Alrhman Masalkhi" <abd.masalkhi@gmail.com>
Cc: yukuai@fygo.io, linux-raid@vger.kernel.org
Subject: Re: [PATCH 2/2] md: add a control device for array management
Date: Mon, 28 Sep 2026 20:26:22 +0000 [thread overview]
Message-ID: <20260928202622.B1EC61F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260928201224.3602262-3-abd.masalkhi@gmail.com>
Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [High] md: MD_STOP_ARRAY mutual exclusion bypass via control device
- [High] md: md_ctl_exit is marked __init and omitted from md_exit()
- [High] md: self-deadlock in get_mddev_dev and get_mddev_uuid via mddev_put
- [Medium] md: binary UUID lookup fails for UUIDs starting with 0x00
- [Medium] md: missing null-termination enforcement allows stack OOB read
- [Low] md: direct cast from __u64 to user pointer causes warnings
- [Low] md: uninitialized pointer passed to get_raid_version()
- [Low] md: unknown ioctl flags return -ENOTTY instead of -EINVAL
- [Low] md: unprivileged un-ratelimited pr_err allows log flooding
--
commit dd168c18138734c235c0b8b1c097fa7a18b6baa8
Author: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Subject: md: add a control device for array management
This patch introduces a misc character device, /dev/md-control, to allow
MD management ioctls without holding a block device reference. New 64-bit
safe ioctls are provided that specify the target array by name, UUID, or
device number.
> The new ioctls use the existing MD_MAJOR ioctl type, starting at 0x40,
> with an MD_ prefix. Every request structure has a flags field. Unknown
> flags are rejected with -EINVAL.
[Severity: Low]
The implementation of ctl_flags_valid() below actually returns -ENOTTY for
unknown flags. Should the implementation be updated to match this documented
behavior?
diff --git a/drivers/md/md-ctl.c b/drivers/md/md-ctl.c
new file mode 100644
index 0000000000000..84923b0a2fa3c
--- /dev/null
+++ b/drivers/md/md-ctl.c
@@ -0,0 +1,597 @@
[ ... ]
+static struct mddev *get_mddev_dev(dev_t dev)
+{
+ struct mddev *mddev, *ret = NULL;
+
+ if (MINOR(dev) >= (1 << MINORBITS))
+ return ERR_PTR(-EINVAL);
+
+ if (MAJOR(dev) != MD_MAJOR)
+ dev &= ~((1 << MdpMinorShift) - 1);
+
+ spin_lock(&all_mddevs_lock);
+ list_for_each_entry(mddev, &all_mddevs, all_mddevs) {
+ if (mddev->unit == dev) {
+ ret = mddev_get(mddev);
+ if (ret && !mddev->gendisk) {
+ mddev_put(mddev);
[Severity: High]
Does calling mddev_put() while holding all_mddevs_lock cause a self-deadlock?
If the reference count was 0 before mddev_get(), mddev_put() will drop it
back to 0 and internally call atomic_dec_and_lock(&mddev->active,
&all_mddevs_lock). Since the current CPU already holds the non-recursive
all_mddevs_lock, this will deadlock the system. This pattern also appears
in get_mddev_uuid().
+ ret = ERR_PTR(-EBUSY);
+ }
+ break;
+ }
+ }
+ spin_unlock(&all_mddevs_lock);
+
+ return ret ? ret : ERR_PTR(-ENODEV);
+}
+
+static struct mddev *get_mddev_name(const char *name)
+{
+ unsigned long minor;
+ struct mddev *mddev, *ret = NULL;
+
+ if (strncmp(name, "md", 2))
+ return ERR_PTR(-EINVAL);
+
+ if (name[2] != '_' && (!isdigit(name[2]) ||
+ kstrtoul(&name[2], 10, &minor) ||
[Severity: Medium]
Can this result in an out-of-bounds read on the kernel stack?
The name field is populated via copy_from_user() on the md_ctl structure
without enforcing null-termination. If a user populates the entire 32-byte
name field without a null terminator, kstrtoul() will read past the array
bounds into adjacent stack memory until it finds a non-digit character.
+ minor > MINORMASK))
+ return ERR_PTR(-EINVAL);
[ ... ]
+static struct mddev *ctl_find_mddev(struct mdu_ioctl *md_ctl)
+{
+ struct mddev *ret = ERR_PTR(-EINVAL);
+
+ if (*md_ctl->uuid) {
[Severity: Medium]
Does this correctly evaluate the binary UUID?
Checking *md_ctl->uuid only evaluates the first byte of the 16-byte array.
If an array is created with a randomly generated UUID that happens to start
with 0x00, the UUID lookup will be skipped and fallback to checking the name
or device number instead.
+ if (*md_ctl->name || md_ctl->dev) {
+ pr_err("md: only supply one of name, uuid or dev number\n");
[Severity: Low]
Could this allow an unprivileged user to flood the kernel log buffer?
Since this is triggered directly by user input via ioctl, using an
un-ratelimited pr_err() here instead of pr_err_ratelimited() or pr_debug()
allows dmesg flooding.
+ return ret;
+ }
[ ... ]
+static long md_ctl_ioctl(struct file *filp, uint cmd, ulong u)
+{
+ int err;
+ unsigned int old_cmd;
+ unsigned int noio_flags = 0;
+ struct mddev *mddev;
+ void __user *arg;
+ struct mdu_ioctl md_ctl;
+
+ err = ctl_ioctl_valid(cmd);
+ if (err)
+ return err;
+
+ if (cmd == MD_RAID_VERSION)
+ return get_raid_version(mddev, (struct mdu_version64 __user *)u);
[Severity: Low]
Does this pass an uninitialized mddev pointer to get_raid_version()?
mddev is evaluated and passed in a register before it is initialized by
ctl_find_mddev(), resulting in undefined behavior.
+
+ if (copy_from_user(&md_ctl, (void __user *)u, sizeof(md_ctl)))
+ return -EFAULT;
+
+ err = ctl_flags_valid(cmd, md_ctl.flags);
+ if (err)
+ return err;
+
+ mddev = ctl_find_mddev(&md_ctl);
+ if (IS_ERR(mddev))
+ return PTR_ERR(mddev);
+
+ old_cmd = try_convert_ioctl_cmd(cmd, md_ctl.flags);
+ if (old_cmd) {
+ err = md_do_ioctl(mddev->gendisk->part0, 0, old_cmd, md_ctl.arg);
[Severity: High]
Does delegating to md_do_ioctl() bypass the MD_STOP_ARRAY mutual exclusion?
When MD_STOP_ARRAY is called here via the control device, md_do_ioctl() calls
mddev_set_closing_and_sync_blockdev(mddev, 1), which assumes the caller holds
the block device open. Because the control ioctl caller doesn't hold the
block device, atomic_read(&mddev->openers) > 1 will evaluate to false if
exactly one other task has the array open, allowing the array to be stopped
while it is actively in use.
+ goto out;
+ }
+
+ arg = (void __user *)md_ctl.arg;
[Severity: Low]
Does this direct cast from __u64 to a pointer cause compiler warnings on
32-bit architectures?
It is recommended to use u64_to_user_ptr() to handle the pointer translation
correctly for compat userspace.
+ switch (cmd) {
[ ... ]
+void __init md_ctl_exit(void)
+{
+ misc_deregister(&md_ctl_misc);
+}
[Severity: High]
Is md_ctl_exit() marked __init by mistake?
Additionally, it appears this function is completely omitted from the
module unload path (md_exit() in md.c doesn't call it). This would leak the
misc device when the md module is unloaded, and any subsequent access to
/dev/md-control would cause a use-after-free panic.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260928201224.3602262-1-abd.masalkhi@gmail.com?part=2
next prev parent reply other threads:[~2026-09-28 20:26 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 20:12 [PATCH 0/2] md: add a control device for array management Abd-Alrhman Masalkhi
2026-09-28 20:12 ` [PATCH 1/2] md: make mddev lookup and ioctl helpers non-static Abd-Alrhman Masalkhi
2026-09-28 20:26 ` sashiko-bot
2026-09-28 20:12 ` [PATCH 2/2] md: add a control device for array management Abd-Alrhman Masalkhi
2026-09-28 20:26 ` sashiko-bot [this message]
2026-09-29 7:38 ` Abd-Alrhman Masalkhi
2026-09-29 4:49 ` Greg KH
2026-09-29 7:12 ` Abd-Alrhman Masalkhi
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=20260928202622.B1EC61F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=abd.masalkhi@gmail.com \
--cc=linux-raid@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--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.