Hi,

Thank you for the report!

+ add UPROBES list to CC.

On 3/9/2026 9:41 PM, Pedro Demarchi Gomes wrote:
> Hi,
> 
> The warning below occurs when running selftests/mm/merge on a kernel built
> with CONFIG_EXT4_DEBUG=y.
> 
> syzkaller login: [   29.277674] ------------[ cut here ]------------
> [   29.279636] WARNING: fs/ext4/inode.c:436 at 
> ext4_check_map_extents_env+0x389/0x440, CPU#1: merge/365
> [   29.282459] Modules linked in:
> [   29.283497] CPU: 1 UID: 0 PID: 365 Comm: merge Not tainted 7.0.0-rc3 #59 
> PREEMPT(full)
> [   29.285999] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 
> 1.16.3-debian-1.16.3-2 04/01/2014
> [   29.288850] RIP: 0010:ext4_check_map_extents_env+0x389/0x440
> [   29.290653] Code: ff 48 89 da 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 80 
> 3c 02 00 0f 85 87 00 00 00 48 8b 45 18 48 85 c0 0f 85 2e fd ff ff 90 <0f> 0b 
> 90 e9 25 fd ff ff e8 8a 2e ca ff e9 e4 fc ff ff 48 89 df e8
> [   29.296623] RSP: 0018:ffff88811876f2a8 EFLAGS: 00010246
> [   29.298288] RAX: 0000000000000000 RBX: ffff888106c66798 RCX: 
> ffffffff81e8ad60
> [   29.300529] RDX: 1ffff11020d8ccf3 RSI: 0000000000000008 RDI: 
> ffff888106c66798
> [   29.302748] RBP: ffff888106c66780 R08: 0000000000000000 R09: 
> ffffed1020d8ccf3
> [   29.305009] R10: ffff888106c6679f R11: 0000000000000001 R12: 
> 00000000001e0c26
> [   29.307226] R13: ffff88811876f494 R14: ffff88811876f498 R15: 
> ffff88811876f488
> [   29.309477] FS:  00007fbe82723780(0000) GS:ffff8883c38aa000(0000) 
> knlGS:0000000000000000
> [   29.312085] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   29.313749] CR2: 00007fbe82790915 CR3: 000000011880e000 CR4: 
> 00000000000006f0
> [   29.315643] Call Trace:
> [   29.316170]  <TASK>
> [   29.316539]  ext4_map_blocks+0x602/0xb40
> [   29.317204]  ? __pfx_ext4_map_blocks+0x10/0x10
> [   29.317971]  ? __pfx_stack_trace_save+0x10/0x10
> [   29.318719]  ? __filemap_add_folio+0x66f/0xb30
> [   29.319500]  ext4_mpage_readpages.constprop.0.isra.0+0x918/0xe20
> [   29.320501]  ? __pfx_ext4_mpage_readpages.constprop.0.isra.0+0x10/0x10
> [   29.321602]  ? filemap_add_folio+0x11e/0x2c0
> [   29.322325]  ? __pfx_ext4_read_folio+0x10/0x10
> [   29.323107]  ext4_read_folio+0xd9/0x230
> [   29.323762]  ? __pfx_ext4_read_folio+0x10/0x10
> [   29.324552]  ? __pfx_ext4_read_folio+0x10/0x10
> [   29.325321]  filemap_read_folio+0x43/0x150
> [   29.326041]  do_read_cache_folio+0x1b1/0x320
> [   29.326759]  read_cache_page+0x46/0x120
> [   29.327426]  install_breakpoint+0x27d/0x810

It seems this isn't an issue with ext4 itself. Instead, the implementation
in uprobe_mmap() seems not respecting the principle that read_cache_page()
should be called while holding mapping->invalidate_lock.

Although the files tracked through uprobe are generally not modified, so
this should not cause a real stale page cache issue. However, I was
wandering why don't we just follow this rule?

Thanks,
Yi.

> [   29.328123]  uprobe_mmap+0x439/0xeb0
> [   29.328715]  ? __pfx_uprobe_mmap+0x10/0x10
> [   29.329391]  __mmap_region+0x8af/0x2290
> [   29.330074]  ? __pfx___mmap_region+0x10/0x10
> [   29.330793]  ? unwind_get_return_address+0x59/0xa0
> [   29.331630]  ? event_sched_in+0x33f/0xaf0
> [   29.332308]  ? perf_event_groups_next+0x9a/0x200
> [   29.333667]  ? mm_get_unmapped_area_vmflags+0x6c/0xe0
> [   29.335295]  ? mmap_region+0xd3/0x2b0
> [   29.336171]  do_mmap+0x98a/0xec0
> [   29.336713]  ? ipe_mmap_file+0xcf/0xe0
> [   29.337340]  ? __pfx_do_mmap+0x10/0x10
> [   29.337977]  ? __pfx_down_write_killable+0x10/0x10
> [   29.338757]  ? __pfx_mutex_unlock+0x10/0x10
> [   29.339477]  vm_mmap_pgoff+0x1b2/0x310
> [   29.340114]  ? __pfx_vm_mmap_pgoff+0x10/0x10
> [   29.340819]  ? __pfx___do_sys_perf_event_open+0x10/0x10
> [   29.341688]  ? fget+0x189/0x230
> [   29.342223]  ksys_mmap_pgoff+0x2b1/0x5b0
> [   29.342868]  ? __pfx_ksys_mmap_pgoff+0x10/0x10
> [   29.343618]  do_syscall_64+0xe2/0x560
> [   29.344246]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> [   29.345105] RIP: 0033:0x7fbe82832de2
> [   29.345707] Code: 00 00 00 0f 1f 44 00 00 41 f7 c1 ff 0f 00 00 75 27 55 89 
> cd 53 48 89 fb 48 85 ff 74 3b 41 89 ea 48 89 df b8 09 00 00 00 0f 05 <48> 3d 
> 00 f0 ff ff 77 76 5b 5d c3 0f 1f 00 48 8b 05 f9 8f 0d 00 64
> [   29.348851] RSP: 002b:00007ffd535f3b38 EFLAGS: 00000206 ORIG_RAX: 
> 0000000000000009
> [   29.350309] RAX: ffffffffffffffda RBX: 00007fbe826f9000 RCX: 
> 00007fbe82832de2
> [   29.351526] RDX: 0000000000000004 RSI: 000000000000a000 RDI: 
> 00007fbe826f9000
> [   29.352865] RBP: 0000000000000012 R08: 000000000000000b R09: 
> 0000000000000000
> [   29.354136] R10: 0000000000000012 R11: 0000000000000206 R12: 
> 00007ffd535f4120
> [   29.355357] R13: 0000000000000000 R14: 000000000000000b R15: 
> 0000000000001000
> [   29.356684]  </TASK>
> [   29.357119] ---[ end trace 0000000000000000 ]---
> 
> The warning is triggered by TEST_F(merge, handle_uprobe_upon_merged_vma) in
> selftests/mm/merge.c. It occurs during the first mmap() following the
> __NR_perf_event_open syscall, as shown in the excerpt below:
> 
> TEST_F(merge, handle_uprobe_upon_merged_vma)
> {
>       const size_t attr_sz = sizeof(struct perf_event_attr);
>       unsigned int page_size = self->page_size;
>       const char *probe_file = "./foo";
>       char *carveout = self->carveout;
>       struct perf_event_attr attr;
>       unsigned long type;
>       void *ptr1, *ptr2;
>       int fd;
> 
>       fd = open(probe_file, O_RDWR|O_CREAT, 0600);
>       ASSERT_GE(fd, 0);
> 
>       ASSERT_EQ(ftruncate(fd, page_size), 0);
>       if (read_sysfs("/sys/bus/event_source/devices/uprobe/type", &type) != 
> 0) {
>               SKIP(goto out, "Failed to read uprobe sysfs file, skipping");
>       }
> 
>       memset(&attr, 0, attr_sz);
>       attr.size = attr_sz;
>       attr.type = type;
>       attr.config1 = (__u64)(long)probe_file;
>       attr.config2 = 0x0;
> 
>       ASSERT_GE(syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0), 0);
> 
>       ptr1 = mmap(&carveout[page_size], 10 * page_size, PROT_EXEC,
>                   MAP_PRIVATE | MAP_FIXED, fd, 0); < WARNING!!!
>       ASSERT_NE(ptr1, MAP_FAILED);
> 
>       getchar();
> 
>       ptr2 = mremap(ptr1, page_size, 2 * page_size,
>                     MREMAP_MAYMOVE | MREMAP_FIXED, ptr1 + 5 * page_size);
>       ASSERT_NE(ptr2, MAP_FAILED);
> 
>       ASSERT_NE(mremap(ptr2, page_size, page_size,
>                        MREMAP_MAYMOVE | MREMAP_FIXED, ptr1), MAP_FAILED);
> 
> out:
>       close(fd);
>       remove(probe_file);
> }
> 
> The issue originates from the following call chain:
>       prepare_uprobe
>         -> copy_insn
>              -> __copy_insn
>                   -> read_mapping_page() or shmem_read_mapping_page()
> 
> Both read_mapping_page() and shmem_read_mapping_page() are invoked
> without holding i_rwsem or invalidate_lock. When CONFIG_EXT4_DEBUG
> is enabled, this triggers the warning in ext4_check_map_extents_env().
> 
> 
> 


Reply via email to