All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ext4: fix discard work use-after-free on failed mount
@ 2026-08-20  5:21 Fan Wu
  2026-08-20  5:44 ` sashiko-bot
  2026-08-20 11:08 ` Jan Kara
  0 siblings, 2 replies; 4+ messages in thread
From: Fan Wu @ 2026-08-20  5:21 UTC (permalink / raw)
  To: tytso
  Cc: adilger.kernel, libaokun, jack, ojaswin, ritesh.list, yi.zhang,
	linux-ext4, linux-kernel, Fan Wu, stable

ext4_put_super() destroys the journal before it calls
ext4_mb_release(), but the failure unwind of __ext4_fill_super() runs
the two steps in the opposite order: failed_mount6 calls
ext4_mb_release(), and the journal is destroyed only later, just above
failed_mount3a.

ext4_mb_release() flushes sbi->s_discard_work before releasing the
mballoc structures, a drain made unconditional in commit 9ee29d20aab2
("ext4: always drain queued discard work in ext4_mb_release()").  With
-o discard, the journal destroy that runs afterwards re-arms that work
after the flush: ext4_journal_destroy() calls ext4_force_commit(), and
the commit callback, registered once mballoc is initialized, queues
s_discard_work whenever the discard option is set, even with an empty
freed-data list.  A quota-enabled mount reaches this with a live
transaction (ext4_enable_quotas() failing into failed_mount8,
ext4_quotas_off() on the failed_mount9 path), so the final force
commit is not a no-op.

Nothing drains s_discard_work after that point: failed_mount3 flushes
only s_sb_upd_work and the s_err_report timer, and ext4_fill_super()
then frees sbi with a plain kfree() through ext4_free_sbi().  If the
system_dfl_wq worker is delayed across the rest of the unwind,
ext4_discard_work() then accesses the freed sbi, first through
sbi->s_sb and then while taking sbi->s_md_lock.

This is the pattern fixed for the s_err_report timer in commit
0ce160c5bdb6 ("ext4: fix timer use-after-free on failed mount"):
async state armed after the unwind's last drain point.

Destroy the journal at failed_mount6, before ext4_mb_release().  This
restores the ext4_put_super() order, so the final commit re-arms
s_discard_work before the flush_work() in ext4_mb_release() drains
it.  The journal destroy further down the unwind still covers paths
that enter below failed_mount6; on the failed_mount6..failed_mount9
paths it does nothing, because ext4_journal_destroy() clears
sbi->s_journal.

This issue was found by an in-house static analysis tool.

Fixes: 55cdd0af2bc5 ("ext4: get discard out of jbd2 commit kthread contex")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
 fs/ext4/super.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 4b6112e5d6c5..58b210637b57 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5761,6 +5761,12 @@ failed_mount8: __maybe_unused
 failed_mount7:
 	ext4_unregister_li_request(sb);
 failed_mount6:
+	/*
+	 * The last commit can re-arm s_discard_work, so destroy the
+	 * journal before ext4_mb_release() flushes it.
+	 */
+	if (sbi->s_journal)
+		ext4_journal_destroy(sbi, sbi->s_journal);
 	ext4_mb_release(sb);
 	ext4_flex_groups_free(sbi);
 failed_mount5:


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-20 12:12 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20  5:21 [PATCH] ext4: fix discard work use-after-free on failed mount Fan Wu
2026-08-20  5:44 ` sashiko-bot
2026-08-20 11:08 ` Jan Kara
2026-08-20 12:12   ` Fan Wu

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.