]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ext4: validate p_idx bounds in ext4_ext_correct_indexes
authorTejas Bharambe <tejas.bharambe@outlook.com>
Wed, 4 Mar 2026 07:14:34 +0000 (23:14 -0800)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 28 Mar 2026 03:33:46 +0000 (23:33 -0400)
ext4_ext_correct_indexes() walks up the extent tree correcting
index entries when the first extent in a leaf is modified. Before
accessing path[k].p_idx->ei_block, there is no validation that
p_idx falls within the valid range of index entries for that
level.

If the on-disk extent header contains a corrupted or crafted
eh_entries value, p_idx can point past the end of the allocated
buffer, causing a slab-out-of-bounds read.

Fix this by validating path[k].p_idx against EXT_LAST_INDEX() at
both access sites: before the while loop and inside it. Return
-EFSCORRUPTED if the index pointer is out of range, consistent
with how other bounds violations are handled in the ext4 extent
tree code.

Reported-by: syzbot+04c4e65cab786a2e5b7e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=04c4e65cab786a2e5b7e
Signed-off-by: Tejas Bharambe <tejas.bharambe@outlook.com>
Link: https://patch.msgid.link/JH0PR06MB66326016F9B6AD24097D232B897CA@JH0PR06MB6632.apcprd06.prod.outlook.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
fs/ext4/extents.c

index b41a44dc245c8b28dc43e915d395c5f8889d776b..c99e0802d700e7774d2065e277525ce0c238b36d 100644 (file)
@@ -1736,6 +1736,13 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
        err = ext4_ext_get_access(handle, inode, path + k);
        if (err)
                return err;
+       if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
+               EXT4_ERROR_INODE(inode,
+                                "path[%d].p_idx %p > EXT_LAST_INDEX %p",
+                                k, path[k].p_idx,
+                                EXT_LAST_INDEX(path[k].p_hdr));
+               return -EFSCORRUPTED;
+       }
        path[k].p_idx->ei_block = border;
        err = ext4_ext_dirty(handle, inode, path + k);
        if (err)
@@ -1748,6 +1755,14 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
                err = ext4_ext_get_access(handle, inode, path + k);
                if (err)
                        goto clean;
+               if (unlikely(path[k].p_idx > EXT_LAST_INDEX(path[k].p_hdr))) {
+                       EXT4_ERROR_INODE(inode,
+                                        "path[%d].p_idx %p > EXT_LAST_INDEX %p",
+                                        k, path[k].p_idx,
+                                        EXT_LAST_INDEX(path[k].p_hdr));
+                       err = -EFSCORRUPTED;
+                       goto clean;
+               }
                path[k].p_idx->ei_block = border;
                err = ext4_ext_dirty(handle, inode, path + k);
                if (err)