When mounting a corrupted ext4 filesystem, the inode's i_extra_isize can be set to a value that leaves insufficient space in the inode for the inline xattr header and entries. While ext4_iget() validates that i_extra_isize fits within the inode size, it does not account for the additional sizeof(ext4_xattr_ibody_header) needed by IHDR/IFIRST. This results in IFIRST(header) pointing at or beyond ITAIL(raw_inode), leaving no room for even the 4-byte terminator entry. When xattr_find_entry() is subsequently called, IS_LAST_ENTRY() reads 4 bytes from this out-of-bounds pointer, triggering a use-after-free. For example, with EXT4_INODE_SIZE=256 and i_extra_isize=124: - ext4_iget() check: 128 + 124 = 252 <= 256, passes - IFIRST = offset 252 + 4 (xattr header) = 256 - ITAIL = 256 - IS_LAST_ENTRY() reads 4 bytes at offset 256, past the inode buffer Fix this by validating in ext4_xattr_ibody_get() that there is enough space between IFIRST(header) and ITAIL for at least a 4-byte read before calling xattr_find_entry(). Return -EFSCORRUPTED if the inline xattr region is too small. Reported-by: syzbot+fb32afec111a7d61b939@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=fb32afec111a7d61b939 Tested-by: syzbot+fb32afec111a7d61b939@syzkaller.appspotmail.com Signed-off-by: Deepanshu Kartikey --- fs/ext4/xattr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 7bf9ba19a89d..5080ec44228a 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -652,6 +652,13 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, header = IHDR(inode, raw_inode); end = ITAIL(inode, raw_inode); entry = IFIRST(header); + + if ((void *)entry + sizeof(__u32) > end) { + EXT4_ERROR_INODE(inode, "inline xattr region overflow"); + error = -EFSCORRUPTED; + goto cleanup; + } + error = xattr_find_entry(inode, &entry, end, name_index, name, 0); if (error) goto cleanup; -- 2.34.1