* [PATCH] ext4: validate extent root during fast commit replay
@ 2026-08-21 10:06 Jérémy Jean
2026-08-21 10:19 ` sashiko-bot
0 siblings, 1 reply; 2+ messages in thread
From: Jérémy Jean @ 2026-08-21 10:06 UTC (permalink / raw)
To: tytso
Cc: adilger.kernel, libaokun, jack, ojaswin, ritesh.list, yi.zhang,
linux-ext4, linux-kernel, Jérémy Jean
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
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] ext4: validate extent root during fast commit replay
2026-08-21 10:06 [PATCH] ext4: validate extent root during fast commit replay Jérémy Jean
@ 2026-08-21 10:19 ` sashiko-bot
0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-08-21 10:19 UTC (permalink / raw)
To: Jérémy Jean; +Cc: linux-ext4, tytso
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Critical] Incomplete fix allows type confusion and out-of-bounds access for indirect-mapped inodes during fast commit replay.
Pre-existing issues:
- [High] Pre-existing error pointer dereference leads to a guaranteed kernel panic, exposed by the new validation check.
--
--- Patch [1]: [PATCH] ext4: validate extent root during fast commit replay ---
commit 03dbc5f9111ce7346c9dc6815dd71904c9c82a55
Author: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
ext4: validate extent root during fast commit replay
This commit adds extent-tree validation for extent-formatted inode roots in
ext4_find_extent() during fast commit replay. It prevents out-of-bounds
memory writes caused by unvalidated extent roots with invalid entry counts.
This addresses an issue where ext4_iget() skips normal validation during
replay.
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 559100f3e23cd..50484f7c3f25e 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -850,6 +850,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))) {
[Severity: Critical]
Could scoping the validation to extent-mapped inodes allow indirect-mapped
inodes to bypass the check?
During fast commit replay, ext4_fc_replay_add_range() unconditionally calls
ext4_find_extent() without ensuring the inode is actually extent-mapped:
fs/ext4/fast_commit.c:ext4_fc_replay_add_range() {
...
if (ret == 0) {
/* Range is not mapped */
path = ext4_find_extent(inode, cur, NULL, 0);
...
}
If an attacker crafts an ext4 image with a fast commit log containing
EXT4_FC_TAG_ADD_RANGE for an inode lacking the EXT4_INODE_EXTENTS flag,
this would bypass the new check and could parse unvalidated indirect block
pointers as an extent header, potentially leading to out-of-bounds access
on EXT4_I(inode)->i_data.
> + ret = ext4_ext_check(inode, eh, depth, 0);
> + if (ret)
> + goto err;
> + }
>
> if (path) {
> ext4_ext_drop_refs(path);
[Severity: High]
This is a pre-existing issue, but does ext4_find_extent() returning
ERR_PTR(-EFSCORRUPTED) lead to a panic in callers that check !path?
For example, in ext4_fc_replay_add_range():
fs/ext4/fast_commit.c:ext4_fc_replay_add_range() {
...
/* Range is not mapped */
path = ext4_find_extent(inode, cur, NULL, 0);
if (!path)
continue;
...
ret = ext4_ext_insert_extent(
NULL, inode, &path, &newex, 0);
...
}
And similarly in ext4_ext_replay_update_ex():
fs/ext4/extents.c:ext4_ext_replay_update_ex() {
...
path = ext4_find_extent(inode, start, NULL, 0);
if (!path)
return -EINVAL;
ex = path[path->p_depth].p_ext;
...
}
Since an ERR_PTR is not NULL, the !path check evaluates to false, causing
the path error pointer to be dereferenced when passed to
ext4_ext_insert_extent() or when accessing path[path->p_depth].p_ext.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260821100559.3612643-2-Jeremy.Jean@oss.cyber.gouv.fr?part=1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-21 10:20 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 10:06 [PATCH] ext4: validate extent root during fast commit replay Jérémy Jean
2026-08-21 10:19 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.