CVE-2026-45899
Description
In the Linux kernel, the following vulnerability has been resolved:
ext4: drop extent cache when splitting extent fails
When the split extent fails, we might leave some extents still being processed and return an error directly, which will result in stale extent entries remaining in the extent status tree. So drop all of the remaining potentially stale extents if the splitting fails.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
In the Linux kernel's ext4 filesystem, a failure during extent splitting can leave stale entries in the extent status tree, potentially causing filesystem corruption.
Vulnerability
In the Linux kernel's ext4 filesystem, when an extent split operation fails, the code may return an error without cleaning up partially processed extents. This leaves stale entries in the extent status tree. The vulnerability affects all versions of the Linux kernel that include the ext4 filesystem code prior to the application of the fix.
Exploitation
An attacker with the ability to perform file operations on an ext4 filesystem can trigger the vulnerability by causing an extent split to fail. This could be achieved through conditions such as disk full, quota limits, or other I/O errors during file operations that require extent splitting. No special privileges beyond normal file access are required.
Impact
Successful exploitation results in stale extent entries remaining in the extent status tree. This can lead to filesystem corruption, data loss, or denial of service as the filesystem may operate on incorrect metadata.
Mitigation
The fix is to drop all remaining potentially stale extents when a split fails. The patch is included in the Linux kernel stable releases via commits referenced in the CVE. Users should update to a kernel version containing these commits. No workaround is available other than applying the patch.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
146e54f8dfee35ext4: drop extent cache when splitting extent fails
2 files changed · +16 −6
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e5b32d5f634a20..6d37805d315507 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3231,7 +3231,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3247,7 +3249,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3303,6 +3306,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e5b32d5f634a20..6d37805d315507 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3231,7 +3231,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3247,7 +3249,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3303,6 +3306,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
337506dc6523ext4: drop extent cache when splitting extent fails
2 files changed · +16 −6
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 54df6fe69d792f..80b7783c65b41e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3236,7 +3236,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3252,7 +3254,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3308,6 +3311,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 54df6fe69d792f..80b7783c65b41e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3236,7 +3236,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3252,7 +3254,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3308,6 +3311,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
808f3191498fext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 37d02e5bbc936a..7402271003fa82 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 37d02e5bbc936a..7402271003fa82 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
79b592e8f1b4ext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1094e492345132..945995d68c4d34 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1094e492345132..945995d68c4d34 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
31bf37cf53edext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index eebb22586163f1..fb3ebfac1b33d1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index eebb22586163f1..fb3ebfac1b33d1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
dc7c9b9d03a5ext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2818d297ce464f..b7e9cbe832121f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3250,7 +3250,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3264,7 +3264,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3341,6 +3341,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2818d297ce464f..b7e9cbe832121f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3250,7 +3250,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3264,7 +3264,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3341,6 +3341,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
120c6bd7ca9dext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9ffdf30eb4fef8..36e42640629705 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3265,7 +3265,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3279,7 +3279,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3356,6 +3356,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9ffdf30eb4fef8..36e42640629705 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3265,7 +3265,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3279,7 +3279,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3356,6 +3356,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
6e54f8dfee35ext4: drop extent cache when splitting extent fails
2 files changed · +16 −6
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e5b32d5f634a20..6d37805d315507 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3231,7 +3231,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3247,7 +3249,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3303,6 +3306,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e5b32d5f634a20..6d37805d315507 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3231,7 +3231,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3247,7 +3249,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3303,6 +3306,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
337506dc6523ext4: drop extent cache when splitting extent fails
2 files changed · +16 −6
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 54df6fe69d792f..80b7783c65b41e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3236,7 +3236,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3252,7 +3254,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3308,6 +3311,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
fs/ext4/extents.c+8 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 54df6fe69d792f..80b7783c65b41e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3236,7 +3236,9 @@ static int ext4_split_extent_at(handle_t *handle, ext4_ext_mark_unwritten(ex2); err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + if (err && err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) + goto out_err; + if (!err) goto out; /* @@ -3252,7 +3254,8 @@ static int ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return PTR_ERR(path); + err = PTR_ERR(path); + goto out_err; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3308,6 +3311,9 @@ fix_extent_len: */ ext4_ext_dirty(handle, inode, path + path->p_depth); return err; +out_err: + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); out: ext4_ext_show_leaf(inode, *ppath); return err; -- cgit 1.3-korg
808f3191498fext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 37d02e5bbc936a..7402271003fa82 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 37d02e5bbc936a..7402271003fa82 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
31bf37cf53edext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index eebb22586163f1..fb3ebfac1b33d1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index eebb22586163f1..fb3ebfac1b33d1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
120c6bd7ca9dext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9ffdf30eb4fef8..36e42640629705 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3265,7 +3265,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3279,7 +3279,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3356,6 +3356,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9ffdf30eb4fef8..36e42640629705 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3265,7 +3265,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3279,7 +3279,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3356,6 +3356,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
dc7c9b9d03a5ext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2818d297ce464f..b7e9cbe832121f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3250,7 +3250,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3264,7 +3264,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3341,6 +3341,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2818d297ce464f..b7e9cbe832121f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3250,7 +3250,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3264,7 +3264,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3341,6 +3341,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
79b592e8f1b4ext4: drop extent cache when splitting extent fails
2 files changed · +12 −6
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1094e492345132..945995d68c4d34 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
fs/ext4/extents.c+6 −3 modifieddiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1094e492345132..945995d68c4d34 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, err = PTR_ERR(path); if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM) - return path; + goto out_path; /* * Get a new path to try to zeroout or fix the extent length. @@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle, if (IS_ERR(path)) { EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld", split, PTR_ERR(path)); - return path; + goto out_path; } depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3358,6 +3358,10 @@ out: ext4_free_ext_path(path); path = ERR_PTR(err); } +out_path: + if (IS_ERR(path)) + /* Remove all remaining potentially stale extents. */ + ext4_es_remove_extent(inode, ee_block, ee_len); ext4_ext_show_leaf(inode, path); return path; } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing cleanup of the extent status tree when ext4_split_extent_at() fails after partially processing extents, leaving stale entries."
Attack vector
An attacker with the ability to trigger filesystem operations that cause extent splitting (e.g., fallocate, write on a fragmented file) on an ext4 filesystem can provoke a failure in ext4_ext_insert_extent() or in a subsequent retry path. When the split fails, the function previously returned an error without removing the extent entries that had already been inserted into the inode's extent status tree. This leaves stale cached extent entries that can cause subsequent I/O to read or write from incorrect disk blocks, potentially leading to data corruption or information disclosure. No special network access is required; the attack vector is local filesystem operations.
Affected code
The vulnerability is in `fs/ext4/extents.c` in the function `ext4_split_extent_at()`. The patch modifies the error handling after `ext4_ext_insert_extent()` and after the `IS_ERR(path)` check to redirect to a new cleanup label instead of returning immediately.
What the fix does
The patch adds a new error-handling label `out_err` (or `out_path` in the upstream variant) that calls `ext4_es_remove_extent(inode, ee_block, ee_len)` to drop all potentially stale extent cache entries before returning the error. In the `ext4_split_extent_at()` function, two early-return paths that previously bypassed cleanup now jump to this new label. The change ensures that whenever the extent split fails after partial progress, the extent status tree is cleaned up, preventing stale cached entries from persisting.
Preconditions
- inputAttacker must be able to perform filesystem operations that trigger extent splitting on an ext4 filesystem (e.g., fallocate, writes to fragmented files).
- configThe filesystem must be mounted and the inode must be in a state where extent splitting can be attempted.
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- git.kernel.org/stable/c/120c6bd7ca9d3e80a968b758cbb3fbd67570f132nvd
- git.kernel.org/stable/c/31bf37cf53ede8145e2bc62da803d4506da92975nvd
- git.kernel.org/stable/c/337506dc652383c80839edb8d8dcdd8ff2129b4fnvd
- git.kernel.org/stable/c/6e54f8dfee359bbd58086c883ea8cffd5312999dnvd
- git.kernel.org/stable/c/79b592e8f1b435796cbc2722190368e3e8ffd7a1nvd
- git.kernel.org/stable/c/808f3191498f300174523c54cab101e18795ae4envd
- git.kernel.org/stable/c/dc7c9b9d03a59a7fe483574531327e650a4b4adcnvd
News mentions
0No linked articles in our index yet.