fs/ext4/extents.c | 7 +++++++ 1 file changed, 7 insertions(+)
During fast commit replay, ext4_iget() skips normal extent-tree
validation. Replay helpers then call ext4_find_extent() and
ext4_ext_insert_extent() on the unchecked inline root.
A corrupted root can advertise more entries than fit in
EXT4_I(inode)->i_data. In particular, eh_entries == 4 and eh_max == 5
make replay insert a fifth extent past i_data and overwrite adjacent
inode fields.
Validate extent-formatted inode roots in ext4_find_extent() during fast
commit replay, before traversal or insertion can trust the header.
Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
---
fs/ext4/extents.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 15972410d460..b95eafb0d5ca 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -905,6 +905,13 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
ret = -EFSCORRUPTED;
goto err;
}
+ /* ext4_iget() skips extent validation during fast commit replay. */
+ if (unlikely((EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) &&
+ ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
+ ret = ext4_ext_check(inode, eh, depth, 0);
+ if (ret)
+ goto err;
+ }
if (path) {
ext4_ext_drop_refs(path);
--
2.47.3
On Fri 21-08-26 10:06:00, Jérémy Jean wrote:
> During fast commit replay, ext4_iget() skips normal extent-tree
> validation. Replay helpers then call ext4_find_extent() and
> ext4_ext_insert_extent() on the unchecked inline root.
>
> A corrupted root can advertise more entries than fit in
> EXT4_I(inode)->i_data. In particular, eh_entries == 4 and eh_max == 5
> make replay insert a fifth extent past i_data and overwrite adjacent
> inode fields.
>
> Validate extent-formatted inode roots in ext4_find_extent() during fast
> commit replay, before traversal or insertion can trust the header.
Hum, I wonder why we don't check extent tree root during fastcommit replay.
From a quick look I don't see the reason. Harhad, Ted, any idea?
Honza
>
> Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
> Assisted-by: Codex:gpt-5
> Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
> ---
> fs/ext4/extents.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 15972410d460..b95eafb0d5ca 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -905,6 +905,13 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
> ret = -EFSCORRUPTED;
> goto err;
> }
> + /* ext4_iget() skips extent validation during fast commit replay. */
> + if (unlikely((EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) &&
> + ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
> + ret = ext4_ext_check(inode, eh, depth, 0);
> + if (ret)
> + goto err;
> + }
>
> if (path) {
> ext4_ext_drop_refs(path);
> --
> 2.47.3
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
© 2016 - 2026 Red Hat, Inc.