public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent
@ 2025-05-25 18:12 syzbot
  2025-05-26 14:53 ` syzbot
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: syzbot @ 2025-05-25 18:12 UTC (permalink / raw)
  To: adilger.kernel, linux-ext4, linux-kernel, syzkaller-bugs, tytso

Hello,

syzbot found the following issue on:

HEAD commit:    d0c22de9995b Merge tag 'input-for-v6.15-rc7' of git://git...
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=15e00df4580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=a1de0d8596cea805
dashboard link: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
compiler:       Debian clang version 20.1.6 (++20250514063057+1e4d39e07757-1~exp1~20250514183223.118), Debian LLD 20.1.6
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=16931170580000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=14683ad4580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/cf852e5656de/disk-d0c22de9.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/761933abe01b/vmlinux-d0c22de9.xz
kernel image: https://storage.googleapis.com/syzbot-assets/187857154891/bzImage-d0c22de9.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/992dec4e0af9/mount_0.gz
  fsck result: failed (log: https://syzkaller.appspot.com/x/fsck.log?x=151468e8580000)

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

==================================================================
BUG: KASAN: slab-use-after-free in ext4_ext_insert_extent+0x41b6/0x4af0 fs/ext4/extents.c:2084
Read of size 4 at addr ffff88802db31c18 by task syz-executor706/7034

CPU: 1 UID: 0 PID: 7034 Comm: syz-executor706 Not tainted 6.15.0-rc7-syzkaller-00152-gd0c22de9995b #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
Call Trace:
 <TASK>
 dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:408 [inline]
 print_report+0xb4/0x290 mm/kasan/report.c:521
 kasan_report+0x118/0x150 mm/kasan/report.c:634
 ext4_ext_insert_extent+0x41b6/0x4af0 fs/ext4/extents.c:2084
 ext4_ext_map_blocks+0x179c/0x67c0 fs/ext4/extents.c:4400
 ext4_map_create_blocks fs/ext4/inode.c:520 [inline]
 ext4_map_blocks+0x807/0x1740 fs/ext4/inode.c:706
 _ext4_get_block+0x200/0x4c0 fs/ext4/inode.c:785
 ext4_get_block_unwritten+0x2e/0x100 fs/ext4/inode.c:818
 ext4_block_write_begin+0x543/0x1290 fs/ext4/inode.c:1067
 ext4_write_begin+0x6f6/0x12c0 fs/ext4/ext4_jbd2.h:-1
 ext4_da_write_begin+0x33a/0xa60 fs/ext4/inode.c:2932
 generic_perform_write+0x2c4/0x910 mm/filemap.c:4103
 ext4_buffered_write_iter+0xce/0x3a0 fs/ext4/file.c:299
 ext4_file_write_iter+0x298/0x1bc0 fs/ext4/file.c:-1
 new_sync_write fs/read_write.c:591 [inline]
 vfs_write+0x54b/0xa90 fs/read_write.c:684
 ksys_pwrite64 fs/read_write.c:791 [inline]
 __do_sys_pwrite64 fs/read_write.c:799 [inline]
 __se_sys_pwrite64 fs/read_write.c:796 [inline]
 __x64_sys_pwrite64+0x193/0x220 fs/read_write.c:796
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f0078162e09
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 b1 18 00 00 90 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 b0 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f0078117218 EFLAGS: 00000246 ORIG_RAX: 0000000000000012
RAX: ffffffffffffffda RBX: 00007f00781ea6c8 RCX: 00007f0078162e09
RDX: 000000000000fdef RSI: 0000200000000140 RDI: 0000000000000004
RBP: 00007f00781ea6c0 R08: 0000000000000000 R09: 0000000000000000
R10: 000000000000fecc R11: 0000000000000246 R12: 00007f00781b7630
R13: 0000200000000000 R14: 00002000000000c0 R15: 00007f00781b706b
 </TASK>

Allocated by task 5844:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
 unpoison_slab_object mm/kasan/common.c:319 [inline]
 __kasan_slab_alloc+0x6c/0x80 mm/kasan/common.c:345
 kasan_slab_alloc include/linux/kasan.h:250 [inline]
 slab_post_alloc_hook mm/slub.c:4147 [inline]
 slab_alloc_node mm/slub.c:4196 [inline]
 kmem_cache_alloc_noprof+0x1c1/0x3c0 mm/slub.c:4203
 getname_flags+0xb8/0x540 fs/namei.c:146
 getname include/linux/fs.h:2852 [inline]
 __do_sys_symlink fs/namei.c:4770 [inline]
 __se_sys_symlink fs/namei.c:4768 [inline]
 __x64_sys_symlink+0x6a/0x90 fs/namei.c:4768
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 5844:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
 kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
 poison_slab_object mm/kasan/common.c:247 [inline]
 __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
 kasan_slab_free include/linux/kasan.h:233 [inline]
 slab_free_hook mm/slub.c:2380 [inline]
 slab_free mm/slub.c:4642 [inline]
 kmem_cache_free+0x192/0x3f0 mm/slub.c:4744
 do_symlinkat+0x39f/0x3f0 fs/namei.c:4757
 __do_sys_symlink fs/namei.c:4770 [inline]
 __se_sys_symlink fs/namei.c:4768 [inline]
 __x64_sys_symlink+0x7a/0x90 fs/namei.c:4768
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88802db31100
 which belongs to the cache names_cache of size 4096
The buggy address is located 2840 bytes inside of
 freed 4096-byte region [ffff88802db31100, ffff88802db32100)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2db30
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
anon flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000040 ffff88801b2b8780 0000000000000000 dead000000000001
raw: 0000000000000000 0000000000070007 00000000f5000000 0000000000000000
head: 00fff00000000040 ffff88801b2b8780 0000000000000000 dead000000000001
head: 0000000000000000 0000000000070007 00000000f5000000 0000000000000000
head: 00fff00000000003 ffffea0000b6cc01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5844, tgid 5844 (udevd), ts 111781614645, free_ts 111672478666
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1d8/0x230 mm/page_alloc.c:1714
 prep_new_page mm/page_alloc.c:1722 [inline]
 get_page_from_freelist+0x21c7/0x22a0 mm/page_alloc.c:3684
 __alloc_frozen_pages_noprof+0x181/0x370 mm/page_alloc.c:4966
 alloc_pages_mpol+0x232/0x4a0 mm/mempolicy.c:2301
 alloc_slab_page mm/slub.c:2450 [inline]
 allocate_slab+0x8a/0x3b0 mm/slub.c:2618
 new_slab mm/slub.c:2672 [inline]
 ___slab_alloc+0xbfc/0x1480 mm/slub.c:3858
 __slab_alloc mm/slub.c:3948 [inline]
 __slab_alloc_node mm/slub.c:4023 [inline]
 slab_alloc_node mm/slub.c:4184 [inline]
 kmem_cache_alloc_noprof+0x283/0x3c0 mm/slub.c:4203
 getname_flags+0xb8/0x540 fs/namei.c:146
 getname include/linux/fs.h:2852 [inline]
 __do_sys_symlink fs/namei.c:4770 [inline]
 __se_sys_symlink fs/namei.c:4768 [inline]
 __x64_sys_symlink+0x5d/0x90 fs/namei.c:4768
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
page last free pid 5189 tgid 5189 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 free_pages_prepare mm/page_alloc.c:1258 [inline]
 __free_frozen_pages+0xb05/0xcd0 mm/page_alloc.c:2721
 discard_slab mm/slub.c:2716 [inline]
 __put_partials+0x161/0x1c0 mm/slub.c:3185
 put_cpu_partial+0x17c/0x250 mm/slub.c:3260
 __slab_free+0x2f7/0x400 mm/slub.c:4512
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x9a/0x140 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:329
 kasan_slab_alloc include/linux/kasan.h:250 [inline]
 slab_post_alloc_hook mm/slub.c:4147 [inline]
 slab_alloc_node mm/slub.c:4196 [inline]
 __do_kmalloc_node mm/slub.c:4326 [inline]
 __kmalloc_noprof+0x224/0x4f0 mm/slub.c:4339
 kmalloc_noprof include/linux/slab.h:909 [inline]
 tomoyo_realpath_from_path+0xe3/0x5d0 security/tomoyo/realpath.c:251
 tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
 tomoyo_path_perm+0x213/0x4b0 security/tomoyo/file.c:822
 security_inode_getattr+0x12f/0x330 security/security.c:2377
 vfs_getattr fs/stat.c:256 [inline]
 vfs_fstat fs/stat.c:278 [inline]
 __do_sys_newfstat fs/stat.c:546 [inline]
 __se_sys_newfstat fs/stat.c:543 [inline]
 __x64_sys_newfstat+0xfe/0x200 fs/stat.c:543
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Memory state around the buggy address:
 ffff88802db31b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff88802db31b80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88802db31c00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                            ^
 ffff88802db31c80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff88802db31d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
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 syzkaller@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

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
@ 2025-05-26 14:53 ` syzbot
  2025-09-30 15:20 ` Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent() syzbot
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-05-26 14:53 UTC (permalink / raw)
  To: adilger.kernel, akpm, dave.hansen, linux-ext4, linux-kernel,
	syzkaller-bugs, tytso

syzbot has bisected this issue to:

commit 665575cff098b696995ddaddf4646a4099941f5e
Author: Dave Hansen <dave.hansen@linux.intel.com>
Date:   Fri Feb 28 20:37:22 2025 +0000

    filemap: move prefaulting out of hot write path

bisection log:  https://syzkaller.appspot.com/x/bisect.txt?x=14435170580000
start commit:   d0c22de9995b Merge tag 'input-for-v6.15-rc7' of git://git...
git tree:       upstream
final oops:     https://syzkaller.appspot.com/x/report.txt?x=16435170580000
console output: https://syzkaller.appspot.com/x/log.txt?x=12435170580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=a1de0d8596cea805
dashboard link: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=16931170580000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=14683ad4580000

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Fixes: 665575cff098 ("filemap: move prefaulting out of hot write path")

For information about bisection process see: https://goo.gl/tpsmEJ#bisection

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent()
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
  2025-05-26 14:53 ` syzbot
@ 2025-09-30 15:20 ` syzbot
  2025-10-01 23:11   ` kernel test robot
  2025-09-30 20:57 ` Forwarded: [PATCH] ext4: fix use-after-free in extent header access syzbot
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: syzbot @ 2025-09-30 15:20 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent()
Author: kartikey406@gmail.com

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

syzbot reported a use-after-free bug in ext4_ext_insert_extent() where
fex->ee_block is accessed after the extent header has been freed. This
occurs when the extent header is corrupted or freed by a concurrent
thread during a write operation.

The issue is triggered when multiple threads perform concurrent writes
to the same file. After commit 665575cff098 ("filemap: move prefaulting
out of hot write path"), the write path no longer prefaults pages,
creating a race window where:

1. Thread A enters ext4_ext_insert_extent() and gets extent header pointer
2. Thread B modifies the extent tree, potentially freeing the header
3. Thread A dereferences fex->ee_block from the freed header, causing UAF

Fix this by validating the extent header's magic number and ensuring it
has valid entries before dereferencing the last extent pointer.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Fixes: 665575cff098 ("filemap: move prefaulting out of hot write path")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..d71b0fff41cc 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2083,6 +2083,12 @@ ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
 	/* probably next leaf has space for us? */
 	fex = EXT_LAST_EXTENT(eh);
 	next = EXT_MAX_BLOCKS;
+	if (le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC ||
+	   le16_to_cpu(eh->eh_entries) == 0) {
+		EXT4_ERROR_INODE(inode, "corrupted extent header");
+		 err = -EFSCORRUPTED;
+		goto errout;
+	}
 	if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
 		next = ext4_ext_next_leaf_block(path);
 	if (next != EXT_MAX_BLOCKS) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: fix use-after-free in extent header access
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
  2025-05-26 14:53 ` syzbot
  2025-09-30 15:20 ` Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent() syzbot
@ 2025-09-30 20:57 ` syzbot
  2025-09-30 22:05 ` syzbot
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-09-30 20:57 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: fix use-after-free in extent header access
Author: kartikey406@gmail.com

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

syzbot reported multiple use-after-free bugs when accessing extent headers
in various ext4 functions. These occur because extent headers can be freed
by concurrent operations while other threads still hold pointers to them.

The issue is triggered by racing threads performing concurrent writes to
the same file. After commit 665575cff098 ("filemap: move prefaulting out
of hot write path"), the write path no longer prefaults pages in the hot
path, creating a wider race window where:

1. Thread A calls ext4_find_extent() and gets a path with extent headers
2. Thread A's write attempt fails, entering the slow path
3. During the gap, Thread B modifies the extent tree, freeing nodes
4. Thread A continues using the now-freed extent headers, causing UAF

Fix this by validating the extent header in ext4_find_extent() before
returning the path. This ensures all callers receive a valid extent path,
fixing the race at a single point rather than adding checks throughout
the codebase.

This addresses crashes in ext4_ext_insert_extent(), ext4_ext_binsearch(),
and potentially other locations that use extent paths.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Fixes: 665575cff098 ("filemap: move prefaulting out of hot write path")
Cc: stable@vger.kernel.org
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..04ceae5b0a34 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4200,6 +4200,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	unsigned int allocated_clusters = 0;
 	struct ext4_allocation_request ar;
 	ext4_lblk_t cluster_offset;
+	struct ext4_extent_header *eh;
 
 	ext_debug(inode, "blocks %u/%u requested\n", map->m_lblk, map->m_len);
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
@@ -4212,7 +4213,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	}
 
 	depth = ext_depth(inode);
-
+	eh = path[depth].p_hdr;
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+		EXT4_ERROR_INODE(inode, "invalid extent header after find_extent");
+		err = -EFSCORRUPTED;
+		goto out;
+	}
 	/*
 	 * consistent leaf must not be empty;
 	 * this situation is possible, though, _during_ tree modification;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: fix use-after-free in extent header access
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
                   ` (2 preceding siblings ...)
  2025-09-30 20:57 ` Forwarded: [PATCH] ext4: fix use-after-free in extent header access syzbot
@ 2025-09-30 22:05 ` syzbot
  2025-09-30 22:49 ` Forwarded: [PATCH] ext4: add defensive checks for extent header corruption syzbot
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-09-30 22:05 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: fix use-after-free in extent header access
Author: kartikey406@gmail.com

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

syzbot reported use-after-free bugs when accessing extent headers in
ext4_ext_insert_extent() and ext4_ext_correct_indexes(). These occur
when the extent path structure becomes invalid during operations.

The crashes show two patterns:
1. In ext4_ext_map_blocks(), the extent header can be corrupted after
   ext4_find_extent() returns, particularly during concurrent writes
   to the same file.
2. In ext4_ext_correct_indexes(), accessing path[depth] causes a
   use-after-free, indicating the path structure itself is corrupted.

This is partially exposed by commit 665575cff098 ("filemap: move
prefaulting out of hot write path") which changed timing windows in
the write path, making these races more likely to occur.

Fix this by adding validation checks:
- In ext4_ext_map_blocks(): validate the extent header after getting
  the path from ext4_find_extent()
- In ext4_ext_correct_indexes(): validate the path pointer before
  dereferencing and check extent header magic

While these checks are defensive and don't address the root cause of
path corruption, they prevent kernel crashes from invalid memory access.
A more comprehensive fix to path lifetime management may be needed in
the future.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Fixes: 665575cff098 ("filemap: move prefaulting out of hot write path")
Cc: stable@vger.kernel.org
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..903578d5f68d 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1708,7 +1708,9 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
 	struct ext4_extent *ex;
 	__le32 border;
 	int k, err = 0;
-
+	if (!path || depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH) {
+		return -EFSCORRUPTED;
+	}
 	eh = path[depth].p_hdr;
 	ex = path[depth].p_ext;
 
@@ -4200,6 +4202,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	unsigned int allocated_clusters = 0;
 	struct ext4_allocation_request ar;
 	ext4_lblk_t cluster_offset;
+	struct ext4_extent_header *eh;
 
 	ext_debug(inode, "blocks %u/%u requested\n", map->m_lblk, map->m_len);
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
@@ -4212,7 +4215,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	}
 
 	depth = ext_depth(inode);
-
+	eh = path[depth].p_hdr;
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+		EXT4_ERROR_INODE(inode, "invalid extent header after find_extent");
+		err = -EFSCORRUPTED;
+		goto out;
+	}
 	/*
 	 * consistent leaf must not be empty;
 	 * this situation is possible, though, _during_ tree modification;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: add defensive checks for extent header corruption
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
                   ` (3 preceding siblings ...)
  2025-09-30 22:05 ` syzbot
@ 2025-09-30 22:49 ` syzbot
  2025-09-30 23:09 ` Forwarded: [PATCH] ext4: add validation checks for corrupted extent headers syzbot
  2025-10-01  0:10 ` syzbot
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-09-30 22:49 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: add defensive checks for extent header corruption
Author: kartikey406@gmail.com

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

syzbot reported use-after-free bugs when accessing extent headers in
multiple locations. Testing revealed crashes in both ext4_ext_map_blocks()
and ext4_ext_correct_indexes() where extent headers or paths contain
invalid data.

The crashes occur when:
1. In ext4_ext_map_blocks(): After ext4_find_extent() returns, the extent
   header at path[depth] can be corrupted
2. In ext4_ext_correct_indexes(): The path structure itself may be invalid
   when accessed at path[depth]

These issues are more easily triggered after commit 665575cff098 ("filemap:
move prefaulting out of hot write path") which changed timing in write
paths, though the underlying vulnerability appears to be pre-existing.

Add defensive validation checks:
- In ext4_ext_map_blocks(): Validate extent header magic after getting path
- In ext4_ext_correct_indexes(): Check path validity before dereferencing

These checks prevent crashes but don't address the root cause of how
these structures become corrupted. Further investigation is needed for
a complete fix.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..04d2328ee1d4 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1708,7 +1708,8 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
 	struct ext4_extent *ex;
 	__le32 border;
 	int k, err = 0;
-
+	if (!path || depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH)
+		return -EFSCORRUPTED;
 	eh = path[depth].p_hdr;
 	ex = path[depth].p_ext;
 
@@ -4200,19 +4201,26 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	unsigned int allocated_clusters = 0;
 	struct ext4_allocation_request ar;
 	ext4_lblk_t cluster_offset;
+	struct ext4_extent_header *eh;
 
 	ext_debug(inode, "blocks %u/%u requested\n", map->m_lblk, map->m_len);
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
-
+	depth = ext_depth(inode);
+	if (depth == 0)
+		eh = ext_inode_hdr(inode);
+	else
+		eh = path[depth].p_hdr;
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+		EXT4_ERROR_INODE(inode, "invalid extent header at depth %d", depth);
+		err = -EFSCORRUPTED;
+		goto out;
+	}
 	/* find extent for this block */
 	path = ext4_find_extent(inode, map->m_lblk, NULL, flags);
 	if (IS_ERR(path)) {
 		err = PTR_ERR(path);
 		goto out;
 	}
-
-	depth = ext_depth(inode);
-
 	/*
 	 * consistent leaf must not be empty;
 	 * this situation is possible, though, _during_ tree modification;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: add validation checks for corrupted extent headers
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
                   ` (4 preceding siblings ...)
  2025-09-30 22:49 ` Forwarded: [PATCH] ext4: add defensive checks for extent header corruption syzbot
@ 2025-09-30 23:09 ` syzbot
  2025-10-01  0:10 ` syzbot
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-09-30 23:09 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: add validation checks for corrupted extent headers
Author: kartikey406@gmail.com

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

syzbot reported use-after-free bugs in extent tree operations, particularly
in ext4_ext_binsearch_idx() and ext4_ext_binsearch() called from
ext4_find_extent(), as well as crashes in ext4_ext_correct_indexes() and
ext4_ext_map_blocks().

The crashes occur when extent headers contain invalid data (wrong magic
number or freed memory). This can happen during concurrent operations on
the same inode where extent tree modifications lead to stale pointers.

Add validation checks at key points:
1. In ext4_find_extent(): validate extent headers before calling
   ext4_ext_binsearch_idx() and ext4_ext_binsearch()
2. In ext4_ext_correct_indexes(): validate path and depth before
   dereferencing path[depth]
3. In ext4_ext_map_blocks(): validate extent header after getting
   the path from ext4_find_extent()

These defensive checks prevent crashes from invalid extent headers,
though the root cause of the corruption needs further investigation.
The checks ensure the code fails gracefully with -EFSCORRUPTED rather
than crashing on invalid memory access.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..ef3870afb8fb 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -930,7 +930,11 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
 	while (i) {
 		ext_debug(inode, "depth %d: num %d, max %d\n",
 			  ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
-
+		if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+			EXT4_ERROR_INODE(inode, "invalid extent header before binsearch_idx");
+			ret = -EFSCORRUPTED;
+			goto err;
+		}
 		ext4_ext_binsearch_idx(inode, path + ppos, block);
 		path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx);
 		path[ppos].p_depth = i;
@@ -952,12 +956,17 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
 	path[ppos].p_ext = NULL;
 	path[ppos].p_idx = NULL;
 
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+		EXT4_ERROR_INODE(inode, "invalid extent header before binsearch");
+		ret = -EFSCORRUPTED;
+		goto err;
+	}
 	/* find extent */
 	ext4_ext_binsearch(inode, path + ppos, block);
 	/* if not an empty leaf */
 	if (path[ppos].p_ext)
 		path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext);
-
+
 	ext4_ext_show_path(inode, path);
 
 	return path;
@@ -1708,7 +1717,8 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
 	struct ext4_extent *ex;
 	__le32 border;
 	int k, err = 0;
-
+	if (!path || depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH)
+		return -EFSCORRUPTED;
 	eh = path[depth].p_hdr;
 	ex = path[depth].p_ext;
 
@@ -4200,6 +4210,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	unsigned int allocated_clusters = 0;
 	struct ext4_allocation_request ar;
 	ext4_lblk_t cluster_offset;
+	struct ext4_extent_header *eh;
 
 	ext_debug(inode, "blocks %u/%u requested\n", map->m_lblk, map->m_len);
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
@@ -4212,7 +4223,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	}
 
 	depth = ext_depth(inode);
-
+	eh = path[depth].p_hdr;
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC) {
+		EXT4_ERROR_INODE(inode, "invalid extent header at depth %d", depth);
+		err = -EFSCORRUPTED;
+		goto out;
+	}
 	/*
 	 * consistent leaf must not be empty;
 	 * this situation is possible, though, _during_ tree modification;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Forwarded: [PATCH] ext4: add validation checks for corrupted extent headers
  2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
                   ` (5 preceding siblings ...)
  2025-09-30 23:09 ` Forwarded: [PATCH] ext4: add validation checks for corrupted extent headers syzbot
@ 2025-10-01  0:10 ` syzbot
  6 siblings, 0 replies; 9+ messages in thread
From: syzbot @ 2025-10-01  0:10 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ext4: add validation checks for corrupted extent headers
Author: kartikey406@gmail.com

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


syzbot reported use-after-free bugs in extent tree operations, particularly
in ext4_ext_binsearch_idx() and ext4_ext_binsearch() called from
ext4_find_extent(), as well as crashes in ext4_ext_correct_indexes() and
ext4_ext_map_blocks().

The crashes occur when extent headers contain invalid data (wrong magic
number or freed memory). This can happen during concurrent operations on
the same inode where extent tree modifications lead to stale pointers.

Add validation checks at key points:
1. In ext4_find_extent(): validate extent headers before calling
   ext4_ext_binsearch_idx() and ext4_ext_binsearch()
2. In ext4_ext_correct_indexes(): validate path and depth before
   dereferencing path[depth]
3. In ext4_ext_map_blocks(): validate extent header after getting
   the path from ext4_find_extent()

These defensive checks prevent crashes from invalid extent headers,
though the root cause of the corruption needs further investigation.
The checks ensure the code fails gracefully with -EFSCORRUPTED rather
than crashing on invalid memory access.

Reported-by: syzbot+9db318d6167044609878@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db318d6167044609878
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 fs/ext4/extents.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ca5499e9412b..fef9db80d65c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -930,7 +930,11 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
 	while (i) {
 		ext_debug(inode, "depth %d: num %d, max %d\n",
 			  ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
-
+		if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC || le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)) {
+			EXT4_ERROR_INODE(inode, "invalid extent header before binsearch_idx");
+			ret = -EFSCORRUPTED;
+			goto err;
+		}
 		ext4_ext_binsearch_idx(inode, path + ppos, block);
 		path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx);
 		path[ppos].p_depth = i;
@@ -952,12 +956,17 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
 	path[ppos].p_ext = NULL;
 	path[ppos].p_idx = NULL;
 
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC || le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)) {
+		EXT4_ERROR_INODE(inode, "invalid extent header before binsearch");
+		ret = -EFSCORRUPTED;
+		goto err;
+	}
 	/* find extent */
 	ext4_ext_binsearch(inode, path + ppos, block);
 	/* if not an empty leaf */
 	if (path[ppos].p_ext)
 		path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext);
-
+
 	ext4_ext_show_path(inode, path);
 
 	return path;
@@ -1708,7 +1717,8 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
 	struct ext4_extent *ex;
 	__le32 border;
 	int k, err = 0;
-
+	if (!path || depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH)
+		return -EFSCORRUPTED;
 	eh = path[depth].p_hdr;
 	ex = path[depth].p_ext;
 
@@ -4200,6 +4210,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	unsigned int allocated_clusters = 0;
 	struct ext4_allocation_request ar;
 	ext4_lblk_t cluster_offset;
+	struct ext4_extent_header *eh;
 
 	ext_debug(inode, "blocks %u/%u requested\n", map->m_lblk, map->m_len);
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
@@ -4212,7 +4223,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 	}
 
 	depth = ext_depth(inode);
-
+	eh = path[depth].p_hdr;
+	if (!eh || le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC || le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max)) {
+		EXT4_ERROR_INODE(inode, "invalid extent header at depth %d", depth);
+		err = -EFSCORRUPTED;
+		goto out;
+	}
 	/*
 	 * consistent leaf must not be empty;
 	 * this situation is possible, though, _during_ tree modification;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent()
  2025-09-30 15:20 ` Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent() syzbot
@ 2025-10-01 23:11   ` kernel test robot
  0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-10-01 23:11 UTC (permalink / raw)
  To: syzbot, linux-kernel, syzkaller-bugs; +Cc: oe-kbuild-all

Hi syzbot,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tytso-ext4/dev]
[also build test WARNING on linus/master v6.17 next-20250929]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/syzbot/Forwarded-PATCH-ext4-fix-use-after-free-in-ext4_ext_insert_extent/20250930-232453
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
patch link:    https://lore.kernel.org/r/68dbf53f.a00a0220.102ee.004a.GAE%40google.com
patch subject: Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent()
config: arc-randconfig-r073-20251001 (https://download.01.org/0day-ci/archive/20251002/202510020639.uRHSs90S-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 13.4.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510020639.uRHSs90S-lkp@intel.com/

New smatch warnings:
fs/ext4/extents.c:2089 ext4_ext_insert_extent() warn: inconsistent indenting

Old smatch warnings:
arch/arc/include/asm/thread_info.h:62 current_thread_info() error: uninitialized symbol 'sp'.
fs/ext4/extents.c:4456 ext4_ext_map_blocks() error: uninitialized symbol 'ex'.
fs/ext4/extents.c:4456 ext4_ext_map_blocks() error: uninitialized symbol 'depth'.

vim +2089 fs/ext4/extents.c

  1969	
  1970	/*
  1971	 * ext4_ext_insert_extent:
  1972	 * tries to merge requested extent into the existing extent or
  1973	 * inserts requested extent as new one into the tree,
  1974	 * creating new leaf in the no-space case.
  1975	 */
  1976	struct ext4_ext_path *
  1977	ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
  1978			       struct ext4_ext_path *path,
  1979			       struct ext4_extent *newext, int gb_flags)
  1980	{
  1981		struct ext4_extent_header *eh;
  1982		struct ext4_extent *ex, *fex;
  1983		struct ext4_extent *nearex; /* nearest extent */
  1984		int depth, len, err = 0;
  1985		ext4_lblk_t next;
  1986		int mb_flags = 0, unwritten;
  1987	
  1988		if (gb_flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
  1989			mb_flags |= EXT4_MB_DELALLOC_RESERVED;
  1990		if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
  1991			EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
  1992			err = -EFSCORRUPTED;
  1993			goto errout;
  1994		}
  1995		depth = ext_depth(inode);
  1996		ex = path[depth].p_ext;
  1997		eh = path[depth].p_hdr;
  1998		if (unlikely(path[depth].p_hdr == NULL)) {
  1999			EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
  2000			err = -EFSCORRUPTED;
  2001			goto errout;
  2002		}
  2003	
  2004		/* try to insert block into found extent and return */
  2005		if (ex && !(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) {
  2006	
  2007			/*
  2008			 * Try to see whether we should rather test the extent on
  2009			 * right from ex, or from the left of ex. This is because
  2010			 * ext4_find_extent() can return either extent on the
  2011			 * left, or on the right from the searched position. This
  2012			 * will make merging more effective.
  2013			 */
  2014			if (ex < EXT_LAST_EXTENT(eh) &&
  2015			    (le32_to_cpu(ex->ee_block) +
  2016			    ext4_ext_get_actual_len(ex) <
  2017			    le32_to_cpu(newext->ee_block))) {
  2018				ex += 1;
  2019				goto prepend;
  2020			} else if ((ex > EXT_FIRST_EXTENT(eh)) &&
  2021				   (le32_to_cpu(newext->ee_block) +
  2022				   ext4_ext_get_actual_len(newext) <
  2023				   le32_to_cpu(ex->ee_block)))
  2024				ex -= 1;
  2025	
  2026			/* Try to append newex to the ex */
  2027			if (ext4_can_extents_be_merged(inode, ex, newext)) {
  2028				ext_debug(inode, "append [%d]%d block to %u:[%d]%d"
  2029					  "(from %llu)\n",
  2030					  ext4_ext_is_unwritten(newext),
  2031					  ext4_ext_get_actual_len(newext),
  2032					  le32_to_cpu(ex->ee_block),
  2033					  ext4_ext_is_unwritten(ex),
  2034					  ext4_ext_get_actual_len(ex),
  2035					  ext4_ext_pblock(ex));
  2036				err = ext4_ext_get_access(handle, inode,
  2037							  path + depth);
  2038				if (err)
  2039					goto errout;
  2040				unwritten = ext4_ext_is_unwritten(ex);
  2041				ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
  2042						+ ext4_ext_get_actual_len(newext));
  2043				if (unwritten)
  2044					ext4_ext_mark_unwritten(ex);
  2045				nearex = ex;
  2046				goto merge;
  2047			}
  2048	
  2049	prepend:
  2050			/* Try to prepend newex to the ex */
  2051			if (ext4_can_extents_be_merged(inode, newext, ex)) {
  2052				ext_debug(inode, "prepend %u[%d]%d block to %u:[%d]%d"
  2053					  "(from %llu)\n",
  2054					  le32_to_cpu(newext->ee_block),
  2055					  ext4_ext_is_unwritten(newext),
  2056					  ext4_ext_get_actual_len(newext),
  2057					  le32_to_cpu(ex->ee_block),
  2058					  ext4_ext_is_unwritten(ex),
  2059					  ext4_ext_get_actual_len(ex),
  2060					  ext4_ext_pblock(ex));
  2061				err = ext4_ext_get_access(handle, inode,
  2062							  path + depth);
  2063				if (err)
  2064					goto errout;
  2065	
  2066				unwritten = ext4_ext_is_unwritten(ex);
  2067				ex->ee_block = newext->ee_block;
  2068				ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
  2069				ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
  2070						+ ext4_ext_get_actual_len(newext));
  2071				if (unwritten)
  2072					ext4_ext_mark_unwritten(ex);
  2073				nearex = ex;
  2074				goto merge;
  2075			}
  2076		}
  2077	
  2078		depth = ext_depth(inode);
  2079		eh = path[depth].p_hdr;
  2080		if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
  2081			goto has_space;
  2082	
  2083		/* probably next leaf has space for us? */
  2084		fex = EXT_LAST_EXTENT(eh);
  2085		next = EXT_MAX_BLOCKS;
  2086		if (le16_to_cpu(eh->eh_magic) != EXT4_EXT_MAGIC ||
  2087		   le16_to_cpu(eh->eh_entries) == 0) {
  2088			EXT4_ERROR_INODE(inode, "corrupted extent header");
> 2089			 err = -EFSCORRUPTED;
  2090			goto errout;
  2091		}
  2092		if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
  2093			next = ext4_ext_next_leaf_block(path);
  2094		if (next != EXT_MAX_BLOCKS) {
  2095			struct ext4_ext_path *npath;
  2096	
  2097			ext_debug(inode, "next leaf block - %u\n", next);
  2098			npath = ext4_find_extent(inode, next, NULL, gb_flags);
  2099			if (IS_ERR(npath)) {
  2100				err = PTR_ERR(npath);
  2101				goto errout;
  2102			}
  2103			BUG_ON(npath->p_depth != path->p_depth);
  2104			eh = npath[depth].p_hdr;
  2105			if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {
  2106				ext_debug(inode, "next leaf isn't full(%d)\n",
  2107					  le16_to_cpu(eh->eh_entries));
  2108				ext4_free_ext_path(path);
  2109				path = npath;
  2110				goto has_space;
  2111			}
  2112			ext_debug(inode, "next leaf has no free space(%d,%d)\n",
  2113				  le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
  2114			ext4_free_ext_path(npath);
  2115		}
  2116	
  2117		/*
  2118		 * There is no free space in the found leaf.
  2119		 * We're gonna add a new leaf in the tree.
  2120		 */
  2121		if (gb_flags & EXT4_GET_BLOCKS_METADATA_NOFAIL)
  2122			mb_flags |= EXT4_MB_USE_RESERVED;
  2123		path = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
  2124						path, newext);
  2125		if (IS_ERR(path))
  2126			return path;
  2127		depth = ext_depth(inode);
  2128		eh = path[depth].p_hdr;
  2129	
  2130	has_space:
  2131		nearex = path[depth].p_ext;
  2132	
  2133		err = ext4_ext_get_access(handle, inode, path + depth);
  2134		if (err)
  2135			goto errout;
  2136	
  2137		if (!nearex) {
  2138			/* there is no extent in this leaf, create first one */
  2139			ext_debug(inode, "first extent in the leaf: %u:%llu:[%d]%d\n",
  2140					le32_to_cpu(newext->ee_block),
  2141					ext4_ext_pblock(newext),
  2142					ext4_ext_is_unwritten(newext),
  2143					ext4_ext_get_actual_len(newext));
  2144			nearex = EXT_FIRST_EXTENT(eh);
  2145		} else {
  2146			if (le32_to_cpu(newext->ee_block)
  2147				   > le32_to_cpu(nearex->ee_block)) {
  2148				/* Insert after */
  2149				ext_debug(inode, "insert %u:%llu:[%d]%d before: "
  2150						"nearest %p\n",
  2151						le32_to_cpu(newext->ee_block),
  2152						ext4_ext_pblock(newext),
  2153						ext4_ext_is_unwritten(newext),
  2154						ext4_ext_get_actual_len(newext),
  2155						nearex);
  2156				nearex++;
  2157			} else {
  2158				/* Insert before */
  2159				BUG_ON(newext->ee_block == nearex->ee_block);
  2160				ext_debug(inode, "insert %u:%llu:[%d]%d after: "
  2161						"nearest %p\n",
  2162						le32_to_cpu(newext->ee_block),
  2163						ext4_ext_pblock(newext),
  2164						ext4_ext_is_unwritten(newext),
  2165						ext4_ext_get_actual_len(newext),
  2166						nearex);
  2167			}
  2168			len = EXT_LAST_EXTENT(eh) - nearex + 1;
  2169			if (len > 0) {
  2170				ext_debug(inode, "insert %u:%llu:[%d]%d: "
  2171						"move %d extents from 0x%p to 0x%p\n",
  2172						le32_to_cpu(newext->ee_block),
  2173						ext4_ext_pblock(newext),
  2174						ext4_ext_is_unwritten(newext),
  2175						ext4_ext_get_actual_len(newext),
  2176						len, nearex, nearex + 1);
  2177				memmove(nearex + 1, nearex,
  2178					len * sizeof(struct ext4_extent));
  2179			}
  2180		}
  2181	
  2182		le16_add_cpu(&eh->eh_entries, 1);
  2183		path[depth].p_ext = nearex;
  2184		nearex->ee_block = newext->ee_block;
  2185		ext4_ext_store_pblock(nearex, ext4_ext_pblock(newext));
  2186		nearex->ee_len = newext->ee_len;
  2187	
  2188	merge:
  2189		/* try to merge extents */
  2190		if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
  2191			ext4_ext_try_to_merge(handle, inode, path, nearex);
  2192	
  2193		/* time to correct all indexes above */
  2194		err = ext4_ext_correct_indexes(handle, inode, path);
  2195		if (err)
  2196			goto errout;
  2197	
  2198		err = ext4_ext_dirty(handle, inode, path + path->p_depth);
  2199		if (err)
  2200			goto errout;
  2201	
  2202		return path;
  2203	
  2204	errout:
  2205		ext4_free_ext_path(path);
  2206		return ERR_PTR(err);
  2207	}
  2208	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-10-01 23:11 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-25 18:12 [syzbot] [ext4?] KASAN: use-after-free Read in ext4_ext_insert_extent syzbot
2025-05-26 14:53 ` syzbot
2025-09-30 15:20 ` Forwarded: [PATCH] ext4: fix use-after-free in ext4_ext_insert_extent() syzbot
2025-10-01 23:11   ` kernel test robot
2025-09-30 20:57 ` Forwarded: [PATCH] ext4: fix use-after-free in extent header access syzbot
2025-09-30 22:05 ` syzbot
2025-09-30 22:49 ` Forwarded: [PATCH] ext4: add defensive checks for extent header corruption syzbot
2025-09-30 23:09 ` Forwarded: [PATCH] ext4: add validation checks for corrupted extent headers syzbot
2025-10-01  0:10 ` syzbot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox