Skip to content

Commit c678bdc

Browse files
LiBaokun96tytso
authored andcommitted
ext4: fix inode use after free in ext4_end_io_rsv_work()
In ext4_io_end_defer_completion(), check if io_end->list_vec is empty to avoid adding an io_end that requires no conversion to the i_rsv_conversion_list, which in turn prevents starting an unnecessary worker. An ext4_emergency_state() check is also added to avoid attempting to abort the journal in an emergency state. Additionally, ext4_put_io_end_defer() is refactored to call ext4_io_end_defer_completion() directly instead of being open-coded. This also prevents starting an unnecessary worker when EXT4_IO_END_FAILED is set but data_err=abort is not enabled. This ensures that the check in ext4_put_io_end_defer() is consistent with the check in ext4_end_bio(). Otherwise, we might add an io_end to the i_rsv_conversion_list and then call ext4_finish_bio(), after which the inode could be freed before ext4_end_io_rsv_work() is called, triggering a use-after-free issue. Fixes: ce51afb ("ext4: abort journal on data writeback failure if in data_err=abort mode") Signed-off-by: Baokun Li <libaokun1@huawei.com> Reviewed-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20250708111504.3208660-1-libaokun@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 9d90762 commit c678bdc

File tree

1 file changed

+8
-8
lines changed

1 file changed

+8
-8
lines changed

fs/ext4/page-io.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,12 @@ static void dump_completed_IO(struct inode *inode, struct list_head *head)
236236

237237
static bool ext4_io_end_defer_completion(ext4_io_end_t *io_end)
238238
{
239-
if (io_end->flag & EXT4_IO_END_UNWRITTEN)
239+
if (io_end->flag & EXT4_IO_END_UNWRITTEN &&
240+
!list_empty(&io_end->list_vec))
240241
return true;
241242
if (test_opt(io_end->inode->i_sb, DATA_ERR_ABORT) &&
242-
io_end->flag & EXT4_IO_END_FAILED)
243+
io_end->flag & EXT4_IO_END_FAILED &&
244+
!ext4_emergency_state(io_end->inode->i_sb))
243245
return true;
244246
return false;
245247
}
@@ -256,6 +258,7 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end)
256258
WARN_ON(!(io_end->flag & EXT4_IO_END_DEFER_COMPLETION));
257259
WARN_ON(io_end->flag & EXT4_IO_END_UNWRITTEN &&
258260
!io_end->handle && sbi->s_journal);
261+
WARN_ON(!io_end->bio);
259262

260263
spin_lock_irqsave(&ei->i_completed_io_lock, flags);
261264
wq = sbi->rsv_conversion_wq;
@@ -318,12 +321,9 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
318321
void ext4_put_io_end_defer(ext4_io_end_t *io_end)
319322
{
320323
if (refcount_dec_and_test(&io_end->count)) {
321-
if (io_end->flag & EXT4_IO_END_FAILED ||
322-
(io_end->flag & EXT4_IO_END_UNWRITTEN &&
323-
!list_empty(&io_end->list_vec))) {
324-
ext4_add_complete_io(io_end);
325-
return;
326-
}
324+
if (ext4_io_end_defer_completion(io_end))
325+
return ext4_add_complete_io(io_end);
326+
327327
ext4_release_io_end(io_end);
328328
}
329329
}

0 commit comments

Comments
 (0)