From ebeb1acb0ced9cbec16655840ab2e0ba9dc78bd1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Oct 2025 10:17:08 +0200 Subject: [PATCH] 5.10-stable patches added patches: ext4-detect-invalid-inline_data-extents-flag-combination.patch jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch --- ...inline_data-extents-flag-combination.patch | 63 ++++++++++++++ ...g-i-o-complete-before-freeing-blocks.patch | 85 +++++++++++++++++++ queue-5.10/series | 2 + 3 files changed, 150 insertions(+) create mode 100644 queue-5.10/ext4-detect-invalid-inline_data-extents-flag-combination.patch create mode 100644 queue-5.10/jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch diff --git a/queue-5.10/ext4-detect-invalid-inline_data-extents-flag-combination.patch b/queue-5.10/ext4-detect-invalid-inline_data-extents-flag-combination.patch new file mode 100644 index 0000000000..abf7635e75 --- /dev/null +++ b/queue-5.10/ext4-detect-invalid-inline_data-extents-flag-combination.patch @@ -0,0 +1,63 @@ +From 1d3ad183943b38eec2acf72a0ae98e635dc8456b Mon Sep 17 00:00:00 2001 +From: Deepanshu Kartikey +Date: Tue, 30 Sep 2025 16:58:10 +0530 +Subject: ext4: detect invalid INLINE_DATA + EXTENTS flag combination + +From: Deepanshu Kartikey + +commit 1d3ad183943b38eec2acf72a0ae98e635dc8456b upstream. + +syzbot reported a BUG_ON in ext4_es_cache_extent() when opening a verity +file on a corrupted ext4 filesystem mounted without a journal. + +The issue is that the filesystem has an inode with both the INLINE_DATA +and EXTENTS flags set: + + EXT4-fs error (device loop0): ext4_cache_extents:545: inode #15: + comm syz.0.17: corrupted extent tree: lblk 0 < prev 66 + +Investigation revealed that the inode has both flags set: + DEBUG: inode 15 - flag=1, i_inline_off=164, has_inline=1, extents_flag=1 + +This is an invalid combination since an inode should have either: +- INLINE_DATA: data stored directly in the inode +- EXTENTS: data stored in extent-mapped blocks + +Having both flags causes ext4_has_inline_data() to return true, skipping +extent tree validation in __ext4_iget(). The unvalidated out-of-order +extents then trigger a BUG_ON in ext4_es_cache_extent() due to integer +underflow when calculating hole sizes. + +Fix this by detecting this invalid flag combination early in ext4_iget() +and rejecting the corrupted inode. + +Cc: stable@kernel.org +Reported-and-tested-by: syzbot+038b7bf43423e132b308@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=038b7bf43423e132b308 +Suggested-by: Zhang Yi +Signed-off-by: Deepanshu Kartikey +Reviewed-by: Zhang Yi +Message-ID: <20250930112810.315095-1-kartikey406@gmail.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4868,6 +4868,14 @@ struct inode *__ext4_iget(struct super_b + } + ei->i_flags = le32_to_cpu(raw_inode->i_flags); + ext4_set_inode_flags(inode, true); ++ /* Detect invalid flag combination - can't have both inline data and extents */ ++ if (ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) && ++ ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { ++ ext4_error_inode(inode, function, line, 0, ++ "inode has both inline data and extents flags"); ++ ret = -EFSCORRUPTED; ++ goto bad_inode; ++ } + inode->i_blocks = ext4_inode_blocks(raw_inode, ei); + ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo); + if (ext4_has_feature_64bit(sb)) diff --git a/queue-5.10/jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch b/queue-5.10/jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch new file mode 100644 index 0000000000..99bdaca9a3 --- /dev/null +++ b/queue-5.10/jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch @@ -0,0 +1,85 @@ +From 3c652c3a71de1d30d72dc82c3bead8deb48eb749 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Tue, 16 Sep 2025 17:33:36 +0800 +Subject: jbd2: ensure that all ongoing I/O complete before freeing blocks + +From: Zhang Yi + +commit 3c652c3a71de1d30d72dc82c3bead8deb48eb749 upstream. + +When releasing file system metadata blocks in jbd2_journal_forget(), if +this buffer has not yet been checkpointed, it may have already been +written back, currently be in the process of being written back, or has +not yet written back. jbd2_journal_forget() calls +jbd2_journal_try_remove_checkpoint() to check the buffer's status and +add it to the current transaction if it has not been written back. This +buffer can only be reallocated after the transaction is committed. + +jbd2_journal_try_remove_checkpoint() attempts to lock the buffer and +check its dirty status while holding the buffer lock. If the buffer has +already been written back, everything proceeds normally. However, there +are two issues. First, the function returns immediately if the buffer is +locked by the write-back process. It does not wait for the write-back to +complete. Consequently, until the current transaction is committed and +the block is reallocated, there is no guarantee that the I/O will +complete. This means that ongoing I/O could write stale metadata to the +newly allocated block, potentially corrupting data. Second, the function +unlocks the buffer as soon as it detects that the buffer is still dirty. +If a concurrent write-back occurs immediately after this unlocking and +before clear_buffer_dirty() is called in jbd2_journal_forget(), data +corruption can theoretically still occur. + +Although these two issues are unlikely to occur in practice since the +undergoing metadata writeback I/O does not take this long to complete, +it's better to explicitly ensure that all ongoing I/O operations are +completed. + +Fixes: 597599268e3b ("jbd2: discard dirty data when forgetting an un-journalled buffer") +Cc: stable@kernel.org +Suggested-by: Jan Kara +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Message-ID: <20250916093337.3161016-2-yi.zhang@huaweicloud.com> +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/jbd2/transaction.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/fs/jbd2/transaction.c ++++ b/fs/jbd2/transaction.c +@@ -1642,6 +1642,7 @@ int jbd2_journal_forget(handle_t *handle + int drop_reserve = 0; + int err = 0; + int was_modified = 0; ++ int wait_for_writeback = 0; + + if (is_handle_aborted(handle)) + return -EROFS; +@@ -1766,18 +1767,22 @@ int jbd2_journal_forget(handle_t *handle + } + + /* +- * The buffer is still not written to disk, we should +- * attach this buffer to current transaction so that the +- * buffer can be checkpointed only after the current +- * transaction commits. ++ * The buffer has not yet been written to disk. We should ++ * either clear the buffer or ensure that the ongoing I/O ++ * is completed, and attach this buffer to current ++ * transaction so that the buffer can be checkpointed only ++ * after the current transaction commits. + */ + clear_buffer_dirty(bh); ++ wait_for_writeback = 1; + __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); + spin_unlock(&journal->j_list_lock); + } + drop: + __brelse(bh); + spin_unlock(&jh->b_state_lock); ++ if (wait_for_writeback) ++ wait_on_buffer(bh); + jbd2_journal_put_journal_head(jh); + if (drop_reserve) { + /* no need to reserve log space for this block -bzzz */ diff --git a/queue-5.10/series b/queue-5.10/series index 717324be64..5a02201487 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -226,3 +226,5 @@ media-pci-ivtv-add-check-for-dma-map-result.patch mm-slab-make-__free-kfree-accept-error-pointers.patch wifi-rt2x00-use-explicitly-signed-or-unsigned-types.patch kvm-arm64-prevent-access-to-vcpu-events-before-init.patch +jbd2-ensure-that-all-ongoing-i-o-complete-before-freeing-blocks.patch +ext4-detect-invalid-inline_data-extents-flag-combination.patch -- 2.47.3