fs/ext4/inline.c | 7 +++++++ 1 file changed, 7 insertions(+)
When looking for an entry in an inlined directory, if e_value_offs is
changed underneath the filesystem by some change in the block device, it
will lead to an out-of-bounds access that KASAN detects as a
use-after-free.
This is a similar problem as fixed by
commit c6b72f5d82b1 ("ext4: avoid OOB when system.data xattr changes underneath the filesystem")
whose fix was to call ext4_xattr_ibody_find() right after reading the
inode with ext4_get_inode_loc() to check the validity of the xattrs.
However, ext4_xattr_ibody_find() only checks xattr names, via
xattr_find_entry(), not e_value_offs.
Fix by calling xattr_check_inode() which performs a full check on the
xattrs in inode.
Reported-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3ee481e21fd75e14c397
Tested-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com
Fixes: 5701875f9609 ("ext4: fix out-of-bound read in ext4_xattr_inode_dec_ref_all()")
Signed-off-by: Raphael Pinsonneault-Thibeault <rpthibeault@gmail.com>
---
changelog
v1 -> v2: change Fixes tag to reflect that ext4_xattr_ibody_find() used to call
xattr_check_inode() until 5701875f9609.
fs/ext4/inline.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 1b094a4f3866..7d46e1e16b52 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1593,6 +1593,13 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
down_read(&EXT4_I(dir)->xattr_sem);
+ if (EXT4_INODE_HAS_XATTR_SPACE(dir)) {
+ ret = xattr_check_inode(dir, IHDR(dir, ext4_raw_inode(&is.iloc)),
+ ITAIL(dir, ext4_raw_inode(&is.iloc)));
+ if (ret)
+ goto out;
+ }
+
ret = ext4_xattr_ibody_find(dir, &i, &is);
if (ret)
goto out;
--
2.43.0
On Wed 12-11-25 13:57:13, Raphael Pinsonneault-Thibeault wrote:
> When looking for an entry in an inlined directory, if e_value_offs is
> changed underneath the filesystem by some change in the block device, it
> will lead to an out-of-bounds access that KASAN detects as a
> use-after-free.
>
> This is a similar problem as fixed by
> commit c6b72f5d82b1 ("ext4: avoid OOB when system.data xattr changes underneath the filesystem")
> whose fix was to call ext4_xattr_ibody_find() right after reading the
> inode with ext4_get_inode_loc() to check the validity of the xattrs.
>
> However, ext4_xattr_ibody_find() only checks xattr names, via
> xattr_find_entry(), not e_value_offs.
>
> Fix by calling xattr_check_inode() which performs a full check on the
> xattrs in inode.
>
> Reported-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=3ee481e21fd75e14c397
> Tested-by: syzbot+3ee481e21fd75e14c397@syzkaller.appspotmail.com
> Fixes: 5701875f9609 ("ext4: fix out-of-bound read in ext4_xattr_inode_dec_ref_all()")
> Signed-off-by: Raphael Pinsonneault-Thibeault <rpthibeault@gmail.com>
When the filesystem is mounted on top of a block device, syzbot cannot
write to it (it disables CONFIG_BLKDEV_WRITE_MOUNTED option). Also there's
no sane way how the filesystem driver could avoid oopses when the block
device's buffer cache is modified while the filesystem is mounted without
unacceptable slowdown so this patch is pointless in my opinion.
The syzbot reproducer you're referencing actually seems to use
LOOP_SET_STATUS ioctl to mess with the loop device while the filesystem is
mounted. Understanding what exactly happens there and modifying the
loopback device driver to forbid that is in my opinion a more sustainable
way to fix problems like this.
Honza
> ---
> changelog
> v1 -> v2: change Fixes tag to reflect that ext4_xattr_ibody_find() used to call
> xattr_check_inode() until 5701875f9609.
>
> fs/ext4/inline.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
> index 1b094a4f3866..7d46e1e16b52 100644
> --- a/fs/ext4/inline.c
> +++ b/fs/ext4/inline.c
> @@ -1593,6 +1593,13 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
>
> down_read(&EXT4_I(dir)->xattr_sem);
>
> + if (EXT4_INODE_HAS_XATTR_SPACE(dir)) {
> + ret = xattr_check_inode(dir, IHDR(dir, ext4_raw_inode(&is.iloc)),
> + ITAIL(dir, ext4_raw_inode(&is.iloc)));
> + if (ret)
> + goto out;
> + }
> +
> ret = ext4_xattr_ibody_find(dir, &i, &is);
> if (ret)
> goto out;
> --
> 2.43.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
© 2016 - 2025 Red Hat, Inc.