For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] ext4: fix bounds check in check_xattrs() to account for IS_LAST_ENTRY() read
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
The bounds check for the next xattr entry in check_xattrs() uses
(void *)next >= end, which allows next to point within sizeof(u32)
bytes of end. On the next iteration, IS_LAST_ENTRY() reads 4 bytes
from next via *(__u32 *)(entry), which can overrun the valid xattr
region and access freed memory.
This is triggered when mounting a corrupted ext4 filesystem where the
inode's i_extra_isize leaves insufficient space for inline xattr
entries. The ACL permission check calls ext4_get_acl() ->
ext4_xattr_ibody_get() -> xattr_find_entry(), which reads past the
inode buffer.
Fix this by changing the check to (void *)next + sizeof(u32) > end,
ensuring there is always enough space for the IS_LAST_ENTRY() read
on the subsequent iteration.
Reported-by: syzbot+fb32afec111a7d61b939@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=fb32afec111a7d61b939
Link: https://lore.kernel.org/all/20260224231429.31361-1-kartikey406@gmail.com/T/ [v1]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
v2: Move the fix to check_xattrs() as suggested by Ted Ts'o, instead
of adding a separate check in ext4_xattr_ibody_get().
---
fs/ext4/xattr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 7bf9ba19a89d..c6205b405efe 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -226,7 +226,7 @@ check_xattrs(struct inode *inode, struct buffer_head *bh,
/* Find the end of the names list */
while (!IS_LAST_ENTRY(e)) {
struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e);
- if ((void *)next >= end) {
+ if ((void *)next + sizeof(u32) > end) {
err_str = "e_name out of bounds";
goto errout;
}
--
2.43.0