All of lore.kernel.org
 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 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.