[BUG] KASAN: slab-use-after-free Read in drm_buddy_alloc_blocks [amdgpu] [syzkaller]

Yang Zi <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hello,

While fuzzing the amdgpu driver on Linux 6.19.10 with a hardware-free
device-model approach on syzkaller, I found a slab-use-after-free (read) 
in the DRM buddy allocator. The faulting object is a drm_buddy_block from 
the drm_buddy_block slab cache (80-byte region).

The bug is reached through DRM_IOCTL_MODE_CREATE_DUMB on amdgpu, but the root
cause is in the generic DRM buddy allocator (drivers/gpu/drm/drm_buddy.c), not
in amdgpu itself.

Root cause analysis:

During a single drm_buddy_alloc_blocks() request, a block B is allocated and
then trimmed via drm_buddy_block_trim(), which marks B free, detaches its
parent, and calls __alloc_range() over B's subtree. __alloc_range() repeatedly
splits blocks (split_block) and pushes the left/right children onto its DFS
list. When a deeper split_block() fails, control reaches the err_undo path
(drm_buddy.c:885), which calls __drm_buddy_free() on a still-free block. The
merge loop in __drm_buddy_free() (drm_buddy.c:209-213) frees the current block
and its buddy via drm_block_free() and climbs upward, re-inserting the merged
block into the free tree.

The problem is that a stale reference to one of the just-freed child blocks
survives in the allocator's traversal/bookkeeping. When the outer allocation
loop then allocates again, it revisits that already-freed block and calls
mark_allocated() -> rbtree_remove() -> rb_erase(&block->rb, root)
(drm_buddy.c:112), reading from the freed rb-node. This is the reported UAF.

Relevant call stacks from the KASAN report:

Use (read), drm_buddy_alloc_blocks -> mark_allocated -> rbtree_remove
(drm_buddy.c:112) -> rb_erase.
Freed, drm_buddy_alloc_blocks -> drm_buddy_block_trim -> __alloc_range
(drm_buddy.c:885) -> __drm_buddy_free -> drm_block_free.
Allocated, drm_buddy_alloc_blocks -> split_block -> drm_block_alloc.
The free task and the use task are the same, so the entire free-then-use cycle
happens within one drm_buddy_alloc_blocks() invocation.

I also found a closely related slab-use-after-free (write) in __drm_buddy_free()
via the amdgpu_vram_mgr free path, which appears to share the same underlying
allocator rollback defect. I am reporting it separately.

The crash report attached below:

==================================================================
BUG: KASAN: slab-use-after-free in __rb_change_child include/linux/rbtree_augmented.h:199 [inline]
BUG: KASAN: slab-use-after-free in __rb_erase_augmented include/linux/rbtree_augmented.h:242 [inline]
BUG: KASAN: slab-use-after-free in rb_erase+0x135/0xe20 lib/rbtree.c:443
Read of size 8 at addr ffff888107266ea8 by task syz.0.131/1294

CPU: 0 UID: 0 PID: 1294 Comm: syz.0.131 Not tainted 6.19.10 #3 PREEMPT(voluntary) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Arch Linux 1.17.0-2-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xa2/0xd0 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0xbc/0x260 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 __rb_change_child include/linux/rbtree_augmented.h:199 [inline]
 __rb_erase_augmented include/linux/rbtree_augmented.h:242 [inline]
 rb_erase+0x135/0xe20 lib/rbtree.c:443
 rbtree_remove drivers/gpu/drm/drm_buddy.c:112 [inline]
 mark_allocated drivers/gpu/drm/drm_buddy.c:132 [inline]
 drm_buddy_alloc_blocks+0x642/0xce0 drivers/gpu/drm/drm_buddy.c:1210
 amdgpu_vram_mgr_new+0x72c/0x10e0 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c:539
 ttm_resource_alloc+0x13b/0x230 drivers/gpu/drm/ttm/ttm_resource.c:392
 ttm_bo_alloc_resource+0x2c7/0x8c0 drivers/gpu/drm/ttm/ttm_bo.c:742
 ttm_bo_validate+0x1e8/0x530 drivers/gpu/drm/ttm/ttm_bo.c:858
 ttm_bo_init_reserved+0x32e/0x480 drivers/gpu/drm/ttm/ttm_bo.c:972
 amdgpu_bo_create+0x6a2/0xe00 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:703
 amdgpu_bo_create_user+0x87/0x100 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:768
 amdgpu_gem_object_create drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:188 [inline]
 amdgpu_mode_dumb_create+0x250/0x400 drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:1259
 drm_mode_create_dumb drivers/gpu/drm/drm_dumb_buffers.c:227 [inline]
 drm_mode_create_dumb_ioctl+0x211/0x2a0 drivers/gpu/drm/drm_dumb_buffers.c:236
 drm_ioctl_kernel+0x23f/0x300 drivers/gpu/drm/drm_ioctl.c:804
 drm_ioctl+0x644/0xac0 drivers/gpu/drm/drm_ioctl.c:901
 amdgpu_drm_ioctl+0xb0/0x120 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c:2996
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd8/0x360 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f38d47a9c6d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 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 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f38d2ddeff8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f38d49d5fa0 RCX: 00007f38d47a9c6d
RDX: 0000200000000040 RSI: 00000000c02064b2 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007f38d49d5fac
R13: 0000000000000000 R14: 00007f38d2ddfce4 R15: 00007ffd443c5027
 </TASK>

Allocated by task 1292:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 unpoison_slab_object mm/kasan/common.c:340 [inline]
 __kasan_slab_alloc+0x4b/0x60 mm/kasan/common.c:366
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:5045 [inline]
 slab_alloc_node mm/slub.c:5355 [inline]
 kmem_cache_alloc_noprof+0x1f3/0x670 mm/slub.c:5362
 drm_block_alloc drivers/gpu/drm/drm_buddy.c:36 [inline]
 split_block+0xa6/0x7f0 drivers/gpu/drm/drm_buddy.c:437
 __alloc_range+0x4c8/0xa30 drivers/gpu/drm/drm_buddy.c:857
 drm_buddy_block_trim+0x721/0x8e0 drivers/gpu/drm/drm_buddy.c:1055
 drm_buddy_alloc_blocks+0xadb/0xce0 drivers/gpu/drm/drm_buddy.c:1241
 amdgpu_vram_mgr_new+0x72c/0x10e0 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c:539
 ttm_resource_alloc+0x13b/0x230 drivers/gpu/drm/ttm/ttm_resource.c:392
 ttm_bo_alloc_resource+0x2c7/0x8c0 drivers/gpu/drm/ttm/ttm_bo.c:742
 ttm_bo_validate+0x1e8/0x530 drivers/gpu/drm/ttm/ttm_bo.c:858
 ttm_bo_init_reserved+0x32e/0x480 drivers/gpu/drm/ttm/ttm_bo.c:972
 amdgpu_bo_create+0x6a2/0xe00 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:703
 amdgpu_bo_create_user+0x87/0x100 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:768
 amdgpu_gem_object_create drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:188 [inline]
 amdgpu_mode_dumb_create+0x250/0x400 drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:1259
 drm_mode_create_dumb drivers/gpu/drm/drm_dumb_buffers.c:227 [inline]
 drm_mode_create_dumb_ioctl+0x211/0x2a0 drivers/gpu/drm/drm_dumb_buffers.c:236
 drm_ioctl_kernel+0x23f/0x300 drivers/gpu/drm/drm_ioctl.c:804
 drm_ioctl+0x644/0xac0 drivers/gpu/drm/drm_ioctl.c:901
 amdgpu_drm_ioctl+0xb0/0x120 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c:2996
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd8/0x360 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 1292:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x3a/0x60 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2580 [inline]
 slab_free mm/slub.c:6791 [inline]
 kmem_cache_free+0x180/0x560 mm/slub.c:6906
 drm_block_free drivers/gpu/drm/drm_buddy.c:53 [inline]
 __drm_buddy_free+0x357/0x5a0 drivers/gpu/drm/drm_buddy.c:213
 __alloc_range+0x9ff/0xa30 drivers/gpu/drm/drm_buddy.c:885
 drm_buddy_block_trim+0x721/0x8e0 drivers/gpu/drm/drm_buddy.c:1055
 drm_buddy_alloc_blocks+0xadb/0xce0 drivers/gpu/drm/drm_buddy.c:1241
 amdgpu_vram_mgr_new+0x72c/0x10e0 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c:539
 ttm_resource_alloc+0x13b/0x230 drivers/gpu/drm/ttm/ttm_resource.c:392
 ttm_bo_alloc_resource+0x2c7/0x8c0 drivers/gpu/drm/ttm/ttm_bo.c:742
 ttm_bo_validate+0x1e8/0x530 drivers/gpu/drm/ttm/ttm_bo.c:858
 ttm_bo_init_reserved+0x32e/0x480 drivers/gpu/drm/ttm/ttm_bo.c:972
 amdgpu_bo_create+0x6a2/0xe00 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:703
 amdgpu_bo_create_user+0x87/0x100 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c:768
 amdgpu_gem_object_create drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:188 [inline]
 amdgpu_mode_dumb_create+0x250/0x400 drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c:1259
 drm_mode_create_dumb drivers/gpu/drm/drm_dumb_buffers.c:227 [inline]
 drm_mode_create_dumb_ioctl+0x211/0x2a0 drivers/gpu/drm/drm_dumb_buffers.c:236
 drm_ioctl_kernel+0x23f/0x300 drivers/gpu/drm/drm_ioctl.c:804
 drm_ioctl+0x644/0xac0 drivers/gpu/drm/drm_ioctl.c:901
 amdgpu_drm_ioctl+0xb0/0x120 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c:2996
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xd8/0x360 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888107266e70
 which belongs to the cache drm_buddy_block of size 80
The buggy address is located 56 bytes inside of
 freed 80-byte region [ffff888107266e70, ffff888107266ec0)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107266
anon flags: 0x200000000000000(node=0|zone=2)
page_type: f5(slab)
raw: 0200000000000000 ffff88810497a780 ffffea0004257d00 dead000000000003
raw: 0000000000000000 0000000000240024 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff888107266d80: fc fc fa fb fb fb fb fb fb fb fb fb fc fc fc fc
 ffff888107266e00: fa fb fb fb fb fb fb fb fb fb fc fc fc fc fa fb
>ffff888107266e80: fb fb fb fb fb fb fb fb fc fc fc fc fa fb fb fb
                                  ^
 ffff888107266f00: fb fb fb fb fb fb fc fc fc fc 00 00 00 00 00 00
 ffff888107266f80: 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================

Regards,
Yang Zi
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.