Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 716b9c23b862 ("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

authored by

hongao and committed by
Theodore Ts'o
3ceda173 ec0a7500

+13 -3
+13 -3
fs/ext4/extents.c
··· 3254 3254 3255 3255 insert_err = PTR_ERR(path); 3256 3256 err = 0; 3257 + if (insert_err != -ENOSPC && insert_err != -EDQUOT && 3258 + insert_err != -ENOMEM) 3259 + goto out_path; 3257 3260 3258 3261 /* 3259 3262 * Get a new path to try to zeroout or fix the extent length. ··· 3273 3270 goto out_path; 3274 3271 } 3275 3272 3273 + depth = ext_depth(inode); 3274 + ex = path[depth].p_ext; 3275 + if (!ex) { 3276 + EXT4_ERROR_INODE(inode, 3277 + "bad extent address lblock: %lu, depth: %d pblock %llu", 3278 + (unsigned long)ee_block, depth, path[depth].p_block); 3279 + err = -EFSCORRUPTED; 3280 + goto out; 3281 + } 3282 + 3276 3283 err = ext4_ext_get_access(handle, inode, path + depth); 3277 3284 if (err) 3278 3285 goto out; 3279 - 3280 - depth = ext_depth(inode); 3281 - ex = path[depth].p_ext; 3282 3286 3283 3287 fix_extent_len: 3284 3288 ex->ee_len = orig_ex.ee_len;