History

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.

hongao committed 7 months ago

Commit 3ceda171 parent ec0a7501 file · +13 −3Browse files

Unified · Split

fs/ext4/extents.c+13−3
@@ -3254,6 +3254,9 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, · 3253 unmodified lines
3254 3254
3255 insert_err = PTR_ERR(path);3255 insert_err = PTR_ERR(path);
3256 err = 0;3256 err = 0;
3257 if (insert_err != -ENOSPC && insert_err != -EDQUOT &&
3258 insert_err != -ENOMEM)
3259 goto out_path;
3257 3260
3258 /*3261 /*
3259 * Get a new path to try to zeroout or fix the extent length.3262 * 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, · 10 unmodified lines
3270 goto out_path;3273 goto out_path;
3271 }3274 }
3272 3275
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
3273 err = ext4_ext_get_access(handle, inode, path + depth);3286 err = ext4_ext_get_access(handle, inode, path + depth);
3274 if (err)3287 if (err)
3275 goto out;3288 goto out;
3276 3289
3277 depth = ext_depth(inode);
3278 ex = path[depth].p_ext;
3279
3280fix_extent_len:3290fix_extent_len:
3281 ex->ee_len = orig_ex.ee_len;3291 ex->ee_len = orig_ex.ee_len;
3282 err = ext4_ext_dirty(handle, inode, path + path->p_depth);3292 err = ext4_ext_dirty(handle, inode, path + path->p_depth);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t