[BUG] ext4: kernel page fault in ext4_xattr_set_entry via ext4_destroy_inline_data_nolock
From: Zw Tang
Date: Mon Mar 09 2026 - 08:19:44 EST
Hi,
I would like to report an ext4 kernel crash that I reproduced on v7.0-rc3
with a syzkaller-generated C reproducer.
A crafted ext4 filesystem image can trigger a kernel page fault in
memmove() called from ext4_xattr_set_entry(), during the inline data
destruction path.
The first crash happens in:
ext4_destroy_inline_data_nolock()
-> ext4_xattr_ibody_set()
-> ext4_xattr_set_entry()
-> memmove()
Kernel:
git tree: torvalds/linux
commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
kernel version: v7.0.0-rc3
hardware: QEMU Ubuntu 24.10
Rreproducer:
C reproducer: https://pastebin.com/raw/T7HRiZc2
console output: https://pastebin.com/raw/iYYf40Ek
kernel config: https://pastebin.com/raw/CnHdTQNm
Crash log
---------
The first Oops is:
BUG: unable to handle page fault for address: ffff88800745d000
#PF: supervisor write access in kernel mode
#PF: error_code(0x0003) - permissions violation
CPU: 0 PID: 285 Comm: repro Not tainted 7.0.0-rc3 #1
RIP: 0010:memmove+0x5f/0x1b0
Call Trace:
ext4_xattr_set_entry+0x870/0xb80
ext4_xattr_ibody_set+0x1a8/0x270
ext4_destroy_inline_data_nolock+0x1b2/0x300
ext4_destroy_inline_data+0x44/0x80
ext4_do_writepages+0x216/0x1aa0
ext4_writepages+0x165/0x3e0
do_writepages+0xe3/0x1d0
filemap_writeback+0x103/0x140
ext4_alloc_da_blocks+0x58/0x110
ext4_release_file+0xef/0x140
__fput+0x1ef/0x550
task_work_run+0x94/0x100
do_exit+0x3bb/0x1260
do_group_exit+0x53/0xf0
__x64_sys_exit_group+0x1c/0x20
This looks like an ext4 bug in the inline-data/xattr interaction path.
Based on the call trace, the crafted ext4 image seems to drive ext4 into
an inconsistent inline-data / inode-body xattr state. During
ext4_destroy_inline_data_nolock(), ext4 updates inode-body xattr entries
through ext4_xattr_ibody_set() and ext4_xattr_set_entry(), and the final
memmove() faults on an invalid address.
So the crash appears to be rooted in ext4_xattr_set_entry(), with
ext4_destroy_inline_data_nolock() being the immediate trigger path.
Thanks,
Zw Tang