Linux RAID subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Li Youhong" <dayou5941@163.com>
Cc: linux-raid@vger.kernel.org, yukuai@fygo.io
Subject: Re: [PATCH v2] md: remove legacy async del_gendisk
Date: Tue, 22 Sep 2026 02:32:06 +0000	[thread overview]
Message-ID: <20260922023206.AA78D1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260922021533.2935172-1-dayou5941@163.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] md: Use-After-Free in md_notify_reboot and md_exit due to unsafe list_for_each_entry_safe
- [High] md: Use-After-Free in md_seq_show when mddev_get fails
- [High] md: sysfs self-deadlock in md_attr_store due to synchronous kobject_del
--

commit 882f6ccb12f02b986de958463cf3afb9ffc46b20
Author: Li Youhong <liyouhong@kylinos.cn>

md: remove legacy async del_gendisk

This commit removes the legacy async del_gendisk path to resolve a lockdep
cycle between major_names_lock, md_misc_wq, and reconfig_mutex. Deletions
are now done synchronously in mddev_unlock() and mddev_put().

Closes: https://syzkaller.appspot.com/bug?extid=68e1f51046d68329940f

> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 680b34a63cb3d..5d9e76f3256be 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
[ ... ]
>  void mddev_put(struct mddev *mddev)
>  {
> +	bool complete_delete;
> +
>  	if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
>  		return;
>  
> -	__mddev_put(mddev);
> +	complete_delete = __mddev_put(mddev);
>  	spin_unlock(&all_mddevs_lock);
> +	if (complete_delete)
> +		mddev_complete_delete(mddev);
>  }

[Severity: High]
Could synchronous kobject_del() on the active path in drivers/md/md.c:mddev_put()
cause a self-deadlock when triggered from a sysfs handler like md_attr_store()?

Writing 'stop' to /sys/block/mdX/md/array_state executes md_attr_store() under
kernfs active protection. The handler calls do_md_stop(), marking the array as
deleted, and then calls mddev_put().

Since mddev_put() now synchronously invokes mddev_complete_delete() ->
kobject_del(), kobject_del() will call kernfs_remove() and block in
kernfs_drain() waiting for the active protection to drop. The calling thread
is holding the active protection itself, causing a deadlock regression.

[ ... ]
> @@ -9041,8 +9042,13 @@ static int md_seq_show(struct seq_file *seq, void *v)
>  	}
>  
>  	mddev = list_entry(v, struct mddev, all_mddevs);
> -	if (!mddev_get(mddev))
> +	if (!mddev_get(mddev)) {
> +		md_seq_flush_delete(seq);
>  		return 0;
> +	}

[Severity: High]
Can this sequence in drivers/md/md.c:md_seq_show() lead to a use-after-free
regression when mddev_get() fails?

If mddev_get() fails (because MD_DELETED is set), the current iterator v is
unpinned. The code then calls md_seq_flush_delete(seq), which temporarily
drops all_mddevs_lock to perform delayed deletion of a previous node.

During this unlocked window, the unpinned current node v could be fully
deleted and freed by a concurrent thread. When md_seq_flush_delete() reacquires
the lock and md_seq_show() returns 0, seq_read() will call md_seq_next(),
which dereferences the now-freed v pointer.

[ ... ]
> @@ -10714,10 +10721,11 @@ EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
>  static int md_notify_reboot(struct notifier_block *this,
>  			    unsigned long code, void *x)
>  {
> -	struct mddev *mddev;
> +	struct mddev *mddev, *tmp;
> +	bool complete_delete;
>  
>  	spin_lock(&all_mddevs_lock);
> -	list_for_each_entry(mddev, &all_mddevs, all_mddevs) {
> +	list_for_each_entry_safe(mddev, tmp, &all_mddevs, all_mddevs) {
>  		if (!mddev_get(mddev))
>  			continue;
>  		spin_unlock(&all_mddevs_lock);

[Severity: High]
Does dropping all_mddevs_lock inside list_for_each_entry_safe() in
drivers/md/md.c:md_notify_reboot() expose tmp to concurrent deletion?

Since list_for_each_entry_safe() caches the next pointer into tmp before
executing the loop body, tmp is unpinned and unprotected during the unlocked
window. Because mddev_put() now performs synchronous deletion, a concurrent
array teardown could drop the last reference to tmp and free its memory. When
the lock is reacquired, the loop advances by reading tmp->all_mddevs.next,
which dereferences freed memory.

[ ... ]
> @@ -11075,20 +11088,15 @@ static __exit void md_exit(void)
>  	remove_proc_entry("mdstat", NULL);
>  
>  	spin_lock(&all_mddevs_lock);
> -	list_for_each_entry(mddev, &all_mddevs, all_mddevs) {
> +	list_for_each_entry_safe(mddev, tmp, &all_mddevs, all_mddevs) {
>  		if (!mddev_get(mddev))
>  			continue;
>  		spin_unlock(&all_mddevs_lock);

[Severity: High]
Similarly, does dropping the lock here in drivers/md/md.c:md_exit() while
holding an unpinned tmp risk list corruption on module exit?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260922021533.2935172-1-dayou5941@163.com?part=1

      reply	other threads:[~2026-09-22  2:32 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-22  2:15 [PATCH v2] md: remove legacy async del_gendisk Li Youhong
2026-09-22  2:32 ` 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=20260922023206.AA78D1F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dayou5941@163.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