Linux RAID subsystem development
 help / color / mirror / Atom feed
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

  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox