Skip to content

Commit 3ceda17

Browse files
hongaootytso
authored andcommitted
ext4: skip split extent recovery on corruption
ext4_split_extent_at() retries after ext4_ext_insert_extent() fails by refinding the original extent and restoring its length. That recovery is only safe for transient resource failures such as -ENOSPC, -EDQUOT, and -ENOMEM. When ext4_ext_insert_extent() fails because the extent tree is already corrupted, ext4_find_extent() can return a leaf path without p_ext. ext4_split_extent_at() then dereferences path[depth].p_ext while trying to fix up the original extent length, causing a NULL pointer dereference while handling a pre-existing filesystem corruption. Do not enter the recovery path for corruption errors, and validate p_ext after refinding the extent before touching it. This keeps the recovery path limited to cases it can actually repair and turns the syzbot-triggered crash into a proper corruption report. Fixes: 716b9c2 ("ext4: refactor split and convert extents") Reported-by: syzbot+1ffa5d865557e51cb604@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=1ffa5d865557e51cb604 Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Zhang Yi <yi.zhang@huawei.com> Signed-off-by: hongao <hongao@uniontech.com> Link: https://patch.msgid.link/EF77870F23FF9C90+20260324015815.35248-1-hongao@uniontech.com Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org
1 parent ec0a750 commit 3ceda17

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

fs/ext4/extents.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3254,6 +3254,9 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
32543254

32553255
insert_err = PTR_ERR(path);
32563256
err = 0;
3257+
if (insert_err != -ENOSPC && insert_err != -EDQUOT &&
3258+
insert_err != -ENOMEM)
3259+
goto out_path;
32573260

32583261
/*
32593262
* Get a new path to try to zeroout or fix the extent length.
@@ -3270,13 +3273,20 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
32703273
goto out_path;
32713274
}
32723275

3276+
depth = ext_depth(inode);
3277+
ex = path[depth].p_ext;
3278+
if (!ex) {
3279+
EXT4_ERROR_INODE(inode,
3280+
"bad extent address lblock: %lu, depth: %d pblock %llu",
3281+
(unsigned long)ee_block, depth, path[depth].p_block);
3282+
err = -EFSCORRUPTED;
3283+
goto out;
3284+
}
3285+
32733286
err = ext4_ext_get_access(handle, inode, path + depth);
32743287
if (err)
32753288
goto out;
32763289

3277-
depth = ext_depth(inode);
3278-
ex = path[depth].p_ext;
3279-
32803290
fix_extent_len:
32813291
ex->ee_len = orig_ex.ee_len;
32823292
err = ext4_ext_dirty(handle, inode, path + path->p_depth);

0 commit comments

Comments
 (0)