[BUG] KASAN: slab-use-after-free in enqueue_timer (re-armed timer on freed skbuff) [mgag200] [syzkaller]

Yang Zi <[email protected]>
Newsgroups gmane.linux.network,gmane.comp.video.dri.devel,gmane.linux.kernel
Message-ID <[email protected]>
Hi,

While fuzzing the kernel with syzkaller (KASAN), I triggered a
slab-use-after-free in the core timer wheel. A periodic (self-rearming) IPv6
addrconf `rs_timer` was fired in softirq after its host skbuff had already been
freed, and its `mod_timer()` wrote into the freed slab slot.

Reproducer summary :

    BUG: KASAN: slab-use-after-free in enqueue_timer+0x59/0x280 kernel/time/timer.c:616
    BUG: KASAN: slab-use-after-free in hlist_add_head include/linux/list.h:1075 [inline]
    Write of size 8 at addr ffff8880164ac28c8 by task syz.0.4/818
    Call trace:
      __run_timers -> expire_timers -> call_timer_fn
        addrconf_rs_timer  net/ipv6/addrconf.c:4061
        addrconf_mod_rs_timer  net/ipv6/addrconf.c:332
        __mod_timer -> enqueue_timer  kernel/time/timer.c:612
          hlist_add_head  list.h:1075   <-- UAF Write (8B)

The corrupted 704-byte object belongs to `skbuff_small_head` (offset 584,
i.e. the embedded timer_list region). It was allocated by an skb that mgag200's
uevent broadcast created during driver registration/probe, and released via
`consume_skb -> skb_free_head -> kfree`. The timer base still holds an active,
rearming RK/RS timer pointing into that freed object; when the softirq fires
it re-queues it, writing 8 bytes and corrupting the freed slab.

Root cause:  a device / driver with an active, self-rearming IPv6 `addrconf` RS
timer is torn down (device removed/unloaded - e.g. mgag200 remove path) without
first cancelling the timer with `del_timer_sync()`. Once the host object is
freed, the pending timer re-arms itself on freed memory (classic mode-B family:
“timer not removed on driver shutdown → cascade UAF”).

The crash stack trace shows below:

BUG: KASAN: slab-use-after-free in hlist_add_head include/linux/list.h:1075 [inline]
BUG: KASAN: slab-use-after-free in enqueue_timer+0x59/0x280 kernel/time/timer.c:616
Write of size 8 at addr ffff8880164288c8 by task syz.0.4/818

CPU: 0 UID: 0 PID: 818 Comm: syz.0.4 Tainted: G        W  O        7.1.0 #2 PREEMPT(lazy) 
Tainted: [W]=WARN, [O]=OOT_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
Call Trace:
 <IRQ>
 dump_stack_lvl+0xa2/0xd0 lib/dump_stack.c:120
 print_address_description+0x77/0x200 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 hlist_add_head include/linux/list.h:1075 [inline]
 enqueue_timer+0x59/0x280 kernel/time/timer.c:616
 __mod_timer+0x625/0x840 kernel/time/timer.c:-1
 addrconf_mod_rs_timer+0x36/0xd0 net/ipv6/addrconf.c:332
 addrconf_rs_timer+0x280/0x320 net/ipv6/addrconf.c:4061
 call_timer_fn+0xfb/0x2c0 kernel/time/timer.c:1748
 expire_timers kernel/time/timer.c:1799 [inline]
 __run_timers kernel/time/timer.c:2374 [inline]
 __run_timer_base+0x4ad/0x6d0 kernel/time/timer.c:2386
 run_timer_base kernel/time/timer.c:2395 [inline]
 run_timer_softirq+0x32/0x70 kernel/time/timer.c:2405
 handle_softirqs+0x1a2/0x560 kernel/softirq.c:622
 __do_softirq kernel/softirq.c:656 [inline]
 invoke_softirq kernel/softirq.c:496 [inline]
 __irq_exit_rcu+0xa7/0x180 kernel/softirq.c:735
 irq_exit_rcu+0x9/0x20 kernel/softirq.c:752
 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1061 [inline]
 sysvec_apic_timer_interrupt+0x6e/0x80 arch/x86/kernel/apic/apic.c:1061
 </IRQ>
 <TASK>
 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
RIP: 0010:__orc_find arch/x86/kernel/unwind_orc.c:103 [inline]
RIP: 0010:orc_module_find arch/x86/kernel/unwind_orc.c:121 [inline]
RIP: 0010:orc_find arch/x86/kernel/unwind_orc.c:248 [inline]
RIP: 0010:unwind_next_frame+0x474/0x14a0 arch/x86/kernel/unwind_orc.c:510
Code: c1 f8 02 49 c1 ed 3f 49 01 c5 49 83 e5 fe 4b 8d 1c 6f 48 89 df e8 7c 8a 50 00 4b 63 04 6f 48 01 d8 4c 39 e0 76 bf 4b 8d 2c 6f <48> 83 c5 fc 49 39 ef 76 c3 48 8b 04 24 48 2b 44 24 30 48 c1 f8 02
RSP: 0018:ffff88800b91e5a0 EFLAGS: 00000202
RAX: ffffffffc002e234 RBX: ffffffffc0283d2c RCX: ffffffff81349f04
RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffffffffc0283d2c
RBP: ffffffffc0283d2c R08: 00000000000200ec R09: ffffffffffffffff
R10: dffffc0000000000 R11: ffffffff814fd3d0 R12: ffffffffc000f3d3
R13: 00000000000016ac R14: ffffffffc026ffac R15: ffffffffc0280fd4
 arch_stack_walk+0x131/0x160 arch/x86/kernel/stacktrace.c:25
 stack_trace_save+0x45/0x70 kernel/stacktrace.c:122
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x72/0x90 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5296 [inline]
 __kmalloc_noprof+0x237/0x6e0 mm/slub.c:5308
 <alloc::raw_vec::RawVecInner>::finish_grow+0x7d/0xb0 [kt_runtime]
 <alloc::raw_vec::RawVec<u8>>::grow_one+0x3f/0x70 [kt_runtime]
 __kerneltracker_log_integer_cmp_with_graph+0x174/0x590 [kt_runtime]
 mgag200_g200_init_registers drivers/gpu/drm/mgag200/mgag200_g200.c:48 [inline] [mgag200]
 mgag200_g200_device_create+0x55df/0x5a40 drivers/gpu/drm/mgag200/mgag200_g200.c:392 [mgag200]
 </TASK>

Allocated by task 814:
 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:4570 [inline]
 slab_alloc_node mm/slub.c:4899 [inline]
 kmem_cache_alloc_node_noprof+0x1db/0x5e0 mm/slub.c:4951
 kmalloc_reserve net/core/skbuff.c:613 [inline]
 __alloc_skb+0x230/0x4a0 net/core/skbuff.c:713
 alloc_skb include/linux/skbuff.h:1385 [inline]
 alloc_uevent_skb+0x5c/0x120 lib/kobject_uevent.c:289
 uevent_net_broadcast_untagged lib/kobject_uevent.c:326 [inline]
 kobject_uevent_net_broadcast+0x23f/0x420 lib/kobject_uevent.c:410
 kobject_uevent_env+0x447/0x450 lib/kobject_uevent.c:611
 driver_register+0x1e2/0x220 drivers/base/driver.c:257
 drm_pci_register_driver_if_modeset+0x125/0xf20 drivers/gpu/drm/mgag200/mgag200_bmc.c:24 [mgag200]
 do_init_module+0x125/0x3f0 kernel/module/main.c:3106
 init_module_from_file kernel/module/main.c:3777 [inline]
 idempotent_init_module kernel/module/main.c:3789 [inline]
 __do_sys_finit_module kernel/module/main.c:3815 [inline]
 __se_sys_finit_module+0x2c7/0x410 kernel/module/main.c:3799
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x14b/0x490 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 135:
 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:2689 [inline]
 slab_free mm/slub.c:6251 [inline]
 kfree+0x1c1/0x550 mm/slub.c:6566
 skb_kfree_head net/core/skbuff.c:1075 [inline]
 skb_free_head net/core/skbuff.c:1087 [inline]
 skb_release_data+0x5a6/0x690 net/core/skbuff.c:1114
 skb_release_all net/core/skbuff.c:1189 [inline]
 __kfree_skb net/core/skbuff.c:1203 [inline]
 consume_skb+0x106/0x180 net/core/skbuff.c:1436
 netlink_recvmsg+0x3a9/0x570 net/netlink/af_netlink.c:1977
 sock_recvmsg_nosec net/socket.c:1138 [inline]
 sock_recvmsg+0x138/0x140 net/socket.c:1160
 ____sys_recvmsg+0xf5/0x280 net/socket.c:2919
 ___sys_recvmsg+0x117/0x300 net/socket.c:2961
 __sys_recvmsg net/socket.c:2994 [inline]
 __do_sys_recvmsg net/socket.c:3000 [inline]
 __se_sys_recvmsg net/socket.c:2997 [inline]
 __x64_sys_recvmsg+0xd5/0x170 net/socket.c:2997
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x14b/0x490 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888016428680
 which belongs to the cache skbuff_small_head of size 704
The buggy address is located 584 bytes inside of
 freed 704-byte region [ffff888016428680, ffff888016428940)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x16428
head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x100000000000040(head|node=0|zone=1)
page_type: f5(slab)
raw: 0100000000000040 ffff888008b8adc0 dead000000000122 0000000000000000
raw: 0000000000000000 0000000800130013 00000000f5000000 0000000000000000
head: 0100000000000040 ffff888008b8adc0 dead000000000122 0000000000000000
head: 0000000000000000 0000000800130013 00000000f5000000 0000000000000000
head: 0100000000000002 ffffffffffffff01 00000000ffffffff 00000000ffffffff
head: ffff8880164291c0 0000000000000000 00000000ffffffff 0000000000000004
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff888016428780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff888016428800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff888016428880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                              ^
 ffff888016428900: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
 ffff888016428980: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb

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.