* [PATCH] md: fix NULL dereference of pers in md_start_sync()
@ 2026-11-06 8:35 Li Youhong
2026-11-06 8:53 ` sashiko-bot
2026-11-08 3:14 ` yu kuai
0 siblings, 2 replies; 3+ messages in thread
From: Li Youhong @ 2026-11-06 8:35 UTC (permalink / raw)
To: song, yukuai
Cc: magiclinan, xiao, linux-raid, linux-kernel, Li Youhong,
syzbot+a53c2918175b36cfd601, stable
From: Li Youhong <liyouhong@kylinos.cn>
md_start_sync() is queued on md_misc_wq to start resync or to
manage spare disks. On a read-only array it calls
remove_and_add_spares(), which ends up in remove_spares() and
invokes pers->hot_remove_disk.
md_start_sync() does not check whether mddev->pers is still
valid before using it. dm-raid stops the array through
md_stop(), which clears pers. If the queued work then runs,
remove_spares() dereferences pers->hot_remove_disk and crashes.
The read-write path has the same exposure in
md_choose_sync_action().
Return via not_running if pers is already gone.
Fixes: db5e653d7c9f ("md: delay choosing sync action to md_start_sync()")
Reported-by: syzbot+a53c2918175b36cfd601@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a53c2918175b36cfd601
Cc: stable@vger.kernel.org
Signed-off-by: Li Youhong <liyouhong@kylinos.cn>
---
drivers/md/md.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 680b34a63cb3..b7e162f52408 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -10286,6 +10286,13 @@ static void md_start_sync(struct work_struct *ws)
noio_flags = memalloc_noio_save();
}
+ /*
+ * md_stop() clears pers. This work may have been queued earlier and
+ * can run after that, so pers may already be NULL here.
+ */
+ if (!mddev->pers)
+ goto not_running;
+
if (!md_is_rdwr(mddev)) {
/*
* On a read-only array we can:
--
2.25.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] md: fix NULL dereference of pers in md_start_sync()
2026-11-06 8:35 [PATCH] md: fix NULL dereference of pers in md_start_sync() Li Youhong
@ 2026-11-06 8:53 ` sashiko-bot
2026-11-08 3:14 ` yu kuai
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-11-06 8:53 UTC (permalink / raw)
To: Li Youhong; +Cc: linux-raid, yukuai
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] md: use-after-free of mddev in md_start_sync() after md_stop()
--
commit 430c0b94e66563acd0f6769283c9a65888eb4dba
Author: Li Youhong <liyouhong@kylinos.cn>
md: fix NULL dereference of pers in md_start_sync()
This commit adds a NULL check for mddev->pers in md_start_sync() to bail
out via not_running if md_stop() has already cleared pers.
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 03e35386a8028..9cafa8d673e82 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -10312,6 +10312,13 @@ static void md_start_sync(struct work_struct *ws)
> noio_flags = memalloc_noio_save();
> }
>
> + /*
> + * md_stop() clears pers. This work may have been queued earlier and
> + * can run after that, so pers may already be NULL here.
> + */
> + if (!mddev->pers)
> + goto not_running;
[Severity: High]
Can md_start_sync() still use mddev after it is freed when dm-raid calls
md_stop()?
Standard md teardown in do_md_stop() calls stop_sync_thread(), which flushes
mddev->sync_work before __md_stop() clears mddev->pers. In contrast,
dm-raid's raid_dtr() calls md_stop(), unlocks reconfig_mutex, flushes only
event_work, and immediately destroys and frees rs without cancelling or
flushing sync_work:
CPU0 CPU1 (kworker)
raid_dtr() md_start_sync()
mddev_lock_nointr(&rs->md)
md_stop(&rs->md)
__md_stop(&rs->md)
mddev->pers = NULL
mddev_unlock(&rs->md)
mddev_lock_nointr(mddev)
if (!mddev->pers)
goto not_running;
...
mddev_unlock(mddev)
raid_set_free(rs)
mddev_destroy(&rs->md)
percpu_ref_exit(&mddev->active_io)
kfree(rs)
__mddev_resume(mddev, false)
test_and_clear_bit(..., &mddev->recovery)
<-- use-after-free
If md_start_sync() starts after raid_dtr() unlocks reconfig_mutex, it can
also access freed mddev memory before reaching the !mddev->pers check, and
the check itself sits after the conditional unlock-and-suspend block that
can drop reconfig_mutex and suspend an already-stopped array.
Should md_stop() (or __md_stop_writes()) flush or cancel mddev->sync_work
before __md_stop() clears mddev->pers?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106083543.249267-1-dayou5941@163.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] md: fix NULL dereference of pers in md_start_sync()
2026-11-06 8:35 [PATCH] md: fix NULL dereference of pers in md_start_sync() Li Youhong
2026-11-06 8:53 ` sashiko-bot
@ 2026-11-08 3:14 ` yu kuai
1 sibling, 0 replies; 3+ messages in thread
From: yu kuai @ 2026-11-08 3:14 UTC (permalink / raw)
To: Li Youhong, song, yu kuai
Cc: magiclinan, xiao, linux-raid, linux-kernel, Li Youhong,
syzbot+a53c2918175b36cfd601, stable
Hi,
在 2026/11/6 16:35, Li Youhong 写道:
> From: Li Youhong <liyouhong@kylinos.cn>
>
> md_start_sync() is queued on md_misc_wq to start resync or to
> manage spare disks. On a read-only array it calls
> remove_and_add_spares(), which ends up in remove_spares() and
> invokes pers->hot_remove_disk.
>
> md_start_sync() does not check whether mddev->pers is still
> valid before using it. dm-raid stops the array through
> md_stop(), which clears pers. If the queued work then runs,
> remove_spares() dereferences pers->hot_remove_disk and crashes.
> The read-write path has the same exposure in
> md_choose_sync_action().
>
> Return via not_running if pers is already gone.
>
> Fixes: db5e653d7c9f ("md: delay choosing sync action to md_start_sync()")
> Reported-by: syzbot+a53c2918175b36cfd601@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=a53c2918175b36cfd601
> Cc: stable@vger.kernel.org
> Signed-off-by: Li Youhong <liyouhong@kylinos.cn>
> ---
> drivers/md/md.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 680b34a63cb3..b7e162f52408 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -10286,6 +10286,13 @@ static void md_start_sync(struct work_struct *ws)
> noio_flags = memalloc_noio_save();
> }
>
> + /*
> + * md_stop() clears pers. This work may have been queued earlier and
> + * can run after that, so pers may already be NULL here.
> + */
> + if (!mddev->pers)
> + goto not_running;
The plain NULL checking is not a correct fix, as md_start_sync() should not be running
after md_stop(), I think the root cause is that dm-raid is missing a call like
stop_sync_thread() to flush the sync_work.
> +
> if (!md_is_rdwr(mddev)) {
> /*
> * On a read-only array we can:
--
Thanks,
Kuai
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-08 3:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06 8:35 [PATCH] md: fix NULL dereference of pers in md_start_sync() Li Youhong
2026-11-06 8:53 ` sashiko-bot
2026-11-08 3:14 ` yu kuai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox