[syzbot] [ext4?] KASAN: use-after-free Read in ext4_read_inline_data

1 view
Skip to first unread message

syzbot

unread,
Jan 12, 2026, 8:31:28 PM (8 hours ago) Jan 12
to adilger...@dilger.ca, linux...@vger.kernel.org, linux-...@vger.kernel.org, syzkall...@googlegroups.com, ty...@mit.edu
Hello,

syzbot found the following issue on:

HEAD commit: 54e82e93ca93 Merge tag 'core_urgent_for_v6.19_rc4' of git:..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=108c5074580000
kernel config: https://syzkaller.appspot.com/x/.config?x=513255d80ab78f2b
dashboard link: https://syzkaller.appspot.com/bug?extid=6986a30df88382d1f7bf
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=17e0df92580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=1641b1fc580000

Downloadable assets:
disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-54e82e93.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/f3befb5f53a4/vmlinux-54e82e93.xz
kernel image: https://storage.googleapis.com/syzbot-assets/92820ca1dbd8/bzImage-54e82e93.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/6baf5cb1e4ff/mount_0.gz
fsck result: failed (log: https://syzkaller.appspot.com/x/fsck.log?x=1317583a580000)

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+6986a3...@syzkaller.appspotmail.com

EXT4-fs (loop0): mounted filesystem 00000000-0000-0000-0000-000000000000 r/w without journal. Quota mode: none.
loop0: detected capacity change from 2048 to 2045
==================================================================
BUG: KASAN: use-after-free in ext4_read_inline_data+0x1d0/0x2c0 fs/ext4/inline.c:214
Read of size 68 at addr ffff8880566c2810 by task syz.0.17/5510

CPU: 0 UID: 0 PID: 5510 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xca/0x240 mm/kasan/report.c:482
kasan_report+0x118/0x150 mm/kasan/report.c:595
check_region_inline mm/kasan/generic.c:-1 [inline]
kasan_check_range+0x2b0/0x2c0 mm/kasan/generic.c:200
__asan_memcpy+0x29/0x70 mm/kasan/shadow.c:105
ext4_read_inline_data+0x1d0/0x2c0 fs/ext4/inline.c:214
ext4_read_inline_dir+0x2b3/0xb80 fs/ext4/inline.c:1405
ext4_readdir+0x3e8/0x3e90 fs/ext4/dir.c:162
iterate_dir+0x399/0x570 fs/readdir.c:108
__do_sys_getdents64 fs/readdir.c:410 [inline]
__se_sys_getdents64+0xe4/0x260 fs/readdir.c:396
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xec/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f97a4b8f7c9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f97a59cc038 EFLAGS: 00000246 ORIG_RAX: 00000000000000d9
RAX: ffffffffffffffda RBX: 00007f97a4de5fa0 RCX: 00007f97a4b8f7c9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000005
RBP: 00007f97a4c13f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f97a4de6038 R14: 00007f97a4de5fa0 R15: 00007fff8c641cb8
</TASK>

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x7fd834db2 pfn:0x566c2
flags: 0x4fff00000000000(node=1|zone=1|lastcpupid=0x7ff)
raw: 04fff00000000000 ffffea000159b0c8 ffffea000159b148 0000000000000000
raw: 00000007fd834db2 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as freed
page last allocated via order 0, migratetype Movable, gfp_mask 0x140dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO|__GFP_COMP), pid 5511, tgid 5511 (rm), ts 103393754947, free_ts 103419734757
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x234/0x290 mm/page_alloc.c:1857
prep_new_page mm/page_alloc.c:1865 [inline]
get_page_from_freelist+0x24e0/0x2580 mm/page_alloc.c:3915
__alloc_frozen_pages_noprof+0x181/0x370 mm/page_alloc.c:5210
alloc_pages_mpol+0x232/0x4a0 mm/mempolicy.c:2486
folio_alloc_mpol_noprof mm/mempolicy.c:2505 [inline]
vma_alloc_folio_noprof+0xe4/0x200 mm/mempolicy.c:2540
folio_prealloc+0x30/0x180 mm/memory.c:-1
alloc_anon_folio mm/memory.c:5165 [inline]
do_anonymous_page mm/memory.c:5222 [inline]
do_pte_missing+0x14e8/0x3330 mm/memory.c:4399
handle_pte_fault mm/memory.c:6273 [inline]
__handle_mm_fault mm/memory.c:6411 [inline]
handle_mm_fault+0x1b26/0x32b0 mm/memory.c:6580
do_user_addr_fault+0xa7c/0x1380 arch/x86/mm/fault.c:1336
handle_page_fault arch/x86/mm/fault.c:1476 [inline]
exc_page_fault+0x71/0xd0 arch/x86/mm/fault.c:1532
asm_exc_page_fault+0x26/0x30 arch/x86/include/asm/idtentry.h:618
page last free pid 5511 tgid 5511 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
free_pages_prepare mm/page_alloc.c:1406 [inline]
free_unref_folios+0xdb3/0x14f0 mm/page_alloc.c:3000
folios_put_refs+0x584/0x670 mm/swap.c:1002
free_pages_and_swap_cache+0x4be/0x520 mm/swap_state.c:358
__tlb_batch_free_encoded_pages mm/mmu_gather.c:136 [inline]
tlb_batch_pages_flush mm/mmu_gather.c:149 [inline]
tlb_flush_mmu_free mm/mmu_gather.c:397 [inline]
tlb_flush_mmu+0x3a0/0x680 mm/mmu_gather.c:404
tlb_finish_mmu+0xc3/0x1d0 mm/mmu_gather.c:497
exit_mmap+0x439/0xb10 mm/mmap.c:1290
__mmput+0x118/0x430 kernel/fork.c:1173
exit_mm+0x169/0x230 kernel/exit.c:581
do_exit+0x627/0x22f0 kernel/exit.c:959
do_group_exit+0x21c/0x2d0 kernel/exit.c:1112
__do_sys_exit_group kernel/exit.c:1123 [inline]
__se_sys_exit_group kernel/exit.c:1121 [inline]
__x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1121
__pfx_syscall_get_nr+0x0/0x10 arch/x86/include/generated/asm/syscalls_64.h:232
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xec/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f

Memory state around the buggy address:
ffff8880566c2700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff8880566c2780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff8880566c2800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff8880566c2880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff8880566c2900: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzk...@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

syzbot

unread,
1:43 AM (3 hours ago) 1:43 AM
to linux-...@vger.kernel.org, syzkall...@googlegroups.com
For archival purposes, forwarding an incoming command email to
linux-...@vger.kernel.org, syzkall...@googlegroups.com.

***

Subject: [PATCH] ext4: add validation and bounds checking in ext4_read_inline_data()
Author: karti...@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

Add comprehensive validation and bounds checking to prevent use-after-free
and out-of-bounds read vulnerabilities in ext4_read_inline_data().

The function previously trusted that:
1. The iloc buffer_head remained valid throughout execution
2. The xattr entry's e_value_offs pointed within valid inode bounds

This led to two critical vulnerabilities:

1. Use-after-free: The iloc->bh buffer could be freed by another thread
between ext4_get_inode_loc() and ext4_read_inline_data(), causing
reads from freed memory.

2. Out-of-bounds read: A corrupted or malicious filesystem image could
set e_value_offs to point outside the inode's xattr area, causing
reads beyond valid memory bounds.

This patch adds validation to:
- Check iloc and iloc->bh are non-NULL
- Verify buffer is still uptodate
- Validate xattr entry pointer is within inode bounds
- Bounds-check e_value_offs against xattr area size
- Ensure the final memcpy source and length stay within valid memory

Additionally, comprehensive debug logging has been added to aid in
diagnosing similar issues in the future.

The fix prevents both memory safety issues by catching invalid states
before the vulnerable memcpy operation at line 228.

Reported-by: syzbot+6986a3...@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6986a30df88382d1f7bf
Signed-off-by: Deepanshu Kartikey <karti...@gmail.com>
---
fs/ext4/inline.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 90 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 1f6bc05593df..f807598e96c9 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -188,16 +188,44 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
struct ext4_xattr_ibody_header *header;
int cp_len = 0;
struct ext4_inode *raw_inode;
+ void *xattr_start, *xattr_end;
+ u32 value_offs;
+ void *source;

if (!len)
return 0;

+ printk(KERN_ERR "ext4_read_inline_data: START - inode=%lu, len=%u\n",
+ inode->i_ino, len);
+
+ /* VALIDATION 1: Check iloc and buffer validity */
+ if (!iloc) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - iloc is NULL\n");
+ return -EFSCORRUPTED;
+ }
+
+ if (!iloc->bh) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - iloc->bh is NULL\n");
+ return -EFSCORRUPTED;
+ }
+
+ printk(KERN_ERR "ext4_read_inline_data: iloc->bh=%px, refcount=%d\n",
+ iloc->bh, atomic_read(&iloc->bh->b_count));
+
+ if (!buffer_uptodate(iloc->bh)) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - buffer not uptodate\n");
+ return -EIO;
+ }
+
BUG_ON(len > EXT4_I(inode)->i_inline_size);

cp_len = min_t(unsigned int, len, EXT4_MIN_INLINE_DATA_SIZE);

raw_inode = ext4_raw_inode(iloc);
+ printk(KERN_ERR "ext4_read_inline_data: raw_inode=%px\n", raw_inode);
+
memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
+ printk(KERN_ERR "ext4_read_inline_data: copied %d bytes from i_block\n", cp_len);

len -= cp_len;
buffer += cp_len;
@@ -208,17 +236,77 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
header = IHDR(inode, raw_inode);
entry = (struct ext4_xattr_entry *)((void *)raw_inode +
EXT4_I(inode)->i_inline_off);
+
+ printk(KERN_ERR "ext4_read_inline_data: header=%px, entry=%px, i_inline_off=%u\n",
+ header, entry, EXT4_I(inode)->i_inline_off);
+
+ /* VALIDATION 2: Calculate and check bounds */
+ xattr_start = (void *)IFIRST(header);
+ xattr_end = (void *)raw_inode + EXT4_INODE_SIZE(inode->i_sb);
+
+ printk(KERN_ERR "ext4_read_inline_data: BOUNDS - xattr_start=%px, xattr_end=%px, size=%ld\n",
+ xattr_start, xattr_end, (long)(xattr_end - xattr_start));
+
+ /* VALIDATION 3: Check entry pointer is within inode */
+ if ((void *)entry < (void *)raw_inode || (void *)entry >= xattr_end) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - entry %px outside inode bounds [%px-%px]\n",
+ entry, raw_inode, xattr_end);
+ ext4_error_inode(inode, __func__, __LINE__, 0,
+ "xattr entry outside inode bounds");
+ return -EFSCORRUPTED;
+ }
+
+ /* VALIDATION 4: Check e_value_offs */
+ value_offs = le16_to_cpu(entry->e_value_offs);
+ printk(KERN_ERR "ext4_read_inline_data: e_value_offs=%u, e_value_size=%u\n",
+ value_offs, le32_to_cpu(entry->e_value_size));
+
+ if (value_offs > (xattr_end - xattr_start)) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - value_offs %u exceeds xattr bounds %ld\n",
+ value_offs, (long)(xattr_end - xattr_start));
+ ext4_error_inode(inode, __func__, __LINE__, 0,
+ "corrupt xattr offset: %u", value_offs);
+ return -EFSCORRUPTED;
+ }
+
len = min_t(unsigned int, len,
(unsigned int)le32_to_cpu(entry->e_value_size));

- memcpy(buffer,
- (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len);
+ /* VALIDATION 5: Check final read bounds */
+ source = xattr_start + value_offs;
+
+ printk(KERN_ERR "ext4_read_inline_data: FINAL CHECK - source=%px, len=%u, end=%px\n",
+ source, len, source + len);
+
+ if (source < (void *)raw_inode) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - source %px before inode start %px\n",
+ source, raw_inode);
+ return -EFSCORRUPTED;
+ }
+
+ if ((source + len) > xattr_end) {
+ printk(KERN_ERR "ext4_read_inline_data: ERROR - read [%px-%px] exceeds inode end %px\n",
+ source, source + len, xattr_end);
+ ext4_error_inode(inode, __func__, __LINE__, 0,
+ "xattr read exceeds inode bounds");
+ return -EFSCORRUPTED;
+ }
+
+ printk(KERN_ERR "ext4_read_inline_data: ABOUT TO MEMCPY - source=%px, dest=%px, len=%u\n",
+ source, buffer, len);
+
+ memcpy(buffer, source, len);
+
+ printk(KERN_ERR "ext4_read_inline_data: memcpy SUCCESS\n");
+
cp_len += len;

out:
+ printk(KERN_ERR "ext4_read_inline_data: DONE - copied %d bytes total\n", cp_len);
return cp_len;
}

+
/*
* write the buffer to the inline inode.
* If 'create' is set, we don't need to do the extra copy in the xattr
--
2.43.0

syzbot

unread,
2:04 AM (3 hours ago) 2:04 AM
to karti...@gmail.com, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+6986a3...@syzkaller.appspotmail.com
Tested-by: syzbot+6986a3...@syzkaller.appspotmail.com

Tested on:

commit: b71e635f Merge tag 'cgroup-for-6.19-rc5-fixes' of git:..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=14f24052580000
kernel config: https://syzkaller.appspot.com/x/.config?x=3027d9a5f96d82ca
dashboard link: https://syzkaller.appspot.com/bug?extid=6986a30df88382d1f7bf
compiler: Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
patch: https://syzkaller.appspot.com/x/patch.diff?x=1237a99a580000

Note: testing is done by a robot and is best-effort only.
Reply all
Reply to author
Forward
0 new messages