From 4c910ac989e7a6d97565a67677a1ee88e2d1a9ad Mon Sep 17 00:00:00 2001 From: Moon Hee Lee Date: Thu, 10 Jul 2025 00:36:59 -0700 Subject: [PATCH] ext4: bail out when INLINE_DATA_FL lacks system.data xattr A syzbot fuzzed image triggered a BUG_ON in ext4_update_inline_data() when an inode had the INLINE_DATA_FL flag set but was missing the system.data extended attribute. ext4_prepare_inline_data() now checks for the presence of that xattr and returns -EFSCORRUPTED if it is missing, preventing corrupted inodes from reaching the update path and triggering a crash. Proof from e2fsck on the fuzzed image: $ e2fsck -fn mount_0 e2fsck 1.47.0 (5-Feb-2023) One or more block group descriptor checksums are invalid. Fix? no Group descriptor 0 checksum is 0x8245, should be 0x353a. IGNORED. Pass 1: Checking inodes, blocks, and sizes Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? no Inode 16, i_blocks is 3298534883346, should be 18. Fix? no Inode 17, i_blocks is 17592186044416, should be 0. Fix? no Pass 2: Checking directory structure Symlink /file0/file1 (inode #14) is invalid. Clear? no Entry 'file1' in /file0 (12) has an incorrect filetype (was 7, should be 0). Fix? no Directory inode 11, block #5, offset 0: directory corrupted Salvage? no e2fsck: aborted syzkaller: ********** WARNING: Filesystem still has errors ********** Signed-off-by: Moon Hee Lee --- fs/ext4/inline.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index a1bbcdf40824..d9dcb0b09e5c 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -399,6 +399,13 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode, static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, loff_t len) { + struct ext4_xattr_ibody_find is = { + .s = { .not_found = -ENODATA, }, + }; + struct ext4_xattr_info i = { + .name_index = EXT4_XATTR_INDEX_SYSTEM, + .name = EXT4_XATTR_SYSTEM_DATA, + }; int ret, size, no_expand; struct ext4_inode_info *ei = EXT4_I(inode); @@ -409,6 +416,19 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, if (size < len) return -ENOSPC; + ret = ext4_get_inode_loc(inode, &is.iloc); + if (ret) + goto out; + + ret = ext4_xattr_ibody_find(inode, &i, &is); + if (ret) + goto out; + + if (is.s.not_found) { + ret = -EFSCORRUPTED; + goto out; + } + ext4_write_lock_xattr(inode, &no_expand); if (ei->i_inline_off) @@ -417,6 +437,8 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, ret = ext4_create_inline_data(handle, inode, len); ext4_write_unlock_xattr(inode, &no_expand); +out: + brelse(is.iloc.bh); return ret; } -- 2.43.0