Skip to content

Commit 0a9c20e

Browse files
committed
Merge: ext4: avoid journaling sb update on error if journal is destroying
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7087 JIRA: https://issues.redhat.com/browse/RHEL-93593 CVE: CVE-2025-22113 Fix BUG_ON due to transaction start on an unmounting journal. Signed-off-by: Brian Foster <bfoster@redhat.com> Approved-by: Xiubo Li <xiubli@redhat.com> Approved-by: Jay Shin <jaeshin@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents de9c5ac + 90f2b79 commit 0a9c20e

File tree

3 files changed

+45
-19
lines changed

3 files changed

+45
-19
lines changed

fs/ext4/ext4.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1834,7 +1834,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
18341834
enum {
18351835
EXT4_MF_MNTDIR_SAMPLED,
18361836
EXT4_MF_FS_ABORTED, /* Fatal error detected */
1837-
EXT4_MF_FC_INELIGIBLE /* Fast commit ineligible */
1837+
EXT4_MF_FC_INELIGIBLE, /* Fast commit ineligible */
1838+
EXT4_MF_JOURNAL_DESTROY /* Journal is in process of destroying */
18381839
};
18391840

18401841
static inline void ext4_set_mount_flag(struct super_block *sb, int bit)

fs/ext4/ext4_jbd2.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,4 +513,33 @@ static inline int ext4_should_dioread_nolock(struct inode *inode)
513513
return 1;
514514
}
515515

516+
/*
517+
* Pass journal explicitly as it may not be cached in the sbi->s_journal in some
518+
* cases
519+
*/
520+
static inline int ext4_journal_destroy(struct ext4_sb_info *sbi, journal_t *journal)
521+
{
522+
int err = 0;
523+
524+
/*
525+
* At this point only two things can be operating on the journal.
526+
* JBD2 thread performing transaction commit and s_sb_upd_work
527+
* issuing sb update through the journal. Once we set
528+
* EXT4_JOURNAL_DESTROY, new ext4_handle_error() calls will not
529+
* queue s_sb_upd_work and ext4_force_commit() makes sure any
530+
* ext4_handle_error() calls from the running transaction commit are
531+
* finished. Hence no new s_sb_upd_work can be queued after we
532+
* flush it here.
533+
*/
534+
ext4_set_mount_flag(sbi->s_sb, EXT4_MF_JOURNAL_DESTROY);
535+
536+
ext4_force_commit(sbi->s_sb);
537+
flush_work(&sbi->s_sb_upd_work);
538+
539+
err = jbd2_journal_destroy(journal);
540+
sbi->s_journal = NULL;
541+
542+
return err;
543+
}
544+
516545
#endif /* _EXT4_JBD2_H */

fs/ext4/super.c

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -704,9 +704,13 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
704704
* In case the fs should keep running, we need to writeout
705705
* superblock through the journal. Due to lock ordering
706706
* constraints, it may not be safe to do it right here so we
707-
* defer superblock flushing to a workqueue.
707+
* defer superblock flushing to a workqueue. We just need to be
708+
* careful when the journal is already shutting down. If we get
709+
* here in that case, just update the sb directly as the last
710+
* transaction won't commit anyway.
708711
*/
709-
if (continue_fs && journal)
712+
if (continue_fs && journal &&
713+
!ext4_test_mount_flag(sb, EXT4_MF_JOURNAL_DESTROY))
710714
schedule_work(&EXT4_SB(sb)->s_sb_upd_work);
711715
else
712716
ext4_commit_super(sb);
@@ -1236,18 +1240,17 @@ static void ext4_put_super(struct super_block *sb)
12361240
ext4_unregister_li_request(sb);
12371241
ext4_quota_off_umount(sb);
12381242

1239-
flush_work(&sbi->s_sb_upd_work);
12401243
destroy_workqueue(sbi->rsv_conversion_wq);
12411244
ext4_release_orphan_info(sb);
12421245

12431246
if (sbi->s_journal) {
12441247
aborted = is_journal_aborted(sbi->s_journal);
1245-
err = jbd2_journal_destroy(sbi->s_journal);
1246-
sbi->s_journal = NULL;
1248+
err = ext4_journal_destroy(sbi, sbi->s_journal);
12471249
if ((err < 0) && !aborted) {
12481250
ext4_abort(sb, -err, "Couldn't clean up the journal");
12491251
}
1250-
}
1252+
} else
1253+
flush_work(&sbi->s_sb_upd_work);
12511254

12521255
ext4_es_unregister_shrinker(sbi);
12531256
timer_shutdown_sync(&sbi->s_err_report);
@@ -4907,10 +4910,7 @@ static int ext4_load_and_init_journal(struct super_block *sb,
49074910
return 0;
49084911

49094912
out:
4910-
/* flush s_sb_upd_work before destroying the journal. */
4911-
flush_work(&sbi->s_sb_upd_work);
4912-
jbd2_journal_destroy(sbi->s_journal);
4913-
sbi->s_journal = NULL;
4913+
ext4_journal_destroy(sbi, sbi->s_journal);
49144914
return -EINVAL;
49154915
}
49164916

@@ -5672,10 +5672,7 @@ failed_mount8: __maybe_unused
56725672
sbi->s_ea_block_cache = NULL;
56735673

56745674
if (sbi->s_journal) {
5675-
/* flush s_sb_upd_work before journal destroy. */
5676-
flush_work(&sbi->s_sb_upd_work);
5677-
jbd2_journal_destroy(sbi->s_journal);
5678-
sbi->s_journal = NULL;
5675+
ext4_journal_destroy(sbi, sbi->s_journal);
56795676
}
56805677
failed_mount3a:
56815678
ext4_es_unregister_shrinker(sbi);
@@ -5962,7 +5959,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
59625959
return journal;
59635960

59645961
out_journal:
5965-
jbd2_journal_destroy(journal);
5962+
ext4_journal_destroy(EXT4_SB(sb), journal);
59665963
out_bdev:
59675964
bdev_fput(bdev_file);
59685965
return NULL;
@@ -6079,8 +6076,7 @@ static int ext4_load_journal(struct super_block *sb,
60796076
EXT4_SB(sb)->s_journal = journal;
60806077
err = ext4_clear_journal_err(sb, es);
60816078
if (err) {
6082-
EXT4_SB(sb)->s_journal = NULL;
6083-
jbd2_journal_destroy(journal);
6079+
ext4_journal_destroy(EXT4_SB(sb), journal);
60846080
return err;
60856081
}
60866082

@@ -6098,7 +6094,7 @@ static int ext4_load_journal(struct super_block *sb,
60986094
return 0;
60996095

61006096
err_out:
6101-
jbd2_journal_destroy(journal);
6097+
ext4_journal_destroy(EXT4_SB(sb), journal);
61026098
return err;
61036099
}
61046100

0 commit comments

Comments
 (0)