=== DF-0033 PANIC EVIDENCE (from dfbsd-qemu/boot.log, serial console) === Three distinct kernel panics were observed from unprivileged user 'maxx' running fdtol_race (rfork(RFPROC|RFTHREAD) peers + concurrent child exit). All three are manifestations of the same root cause: the lost-update race on the plain-int fdtol->fdl_refcount (incremented under per-proc p_token in fork1, decremented under the shared fd_spin in fdfree) -> premature free of fdtol -> UAF. The race is intermittent (CVSS AC:H); reproducing typically needs several 20-60s bursts of hammering. All three panics below occurred across burst-loop runs. -------------------------------------------------------------------------------- PANIC A (DEFINITIVE) -- the KASSERT at kern_descrip.c:2627-2629 catching the refcount invariant violation directly. fdl_refcount underflowed to 0 while a process still held a live reference and was entering fdfree. -------------------------------------------------------------------------------- login: panic with 1 spinlocks held panic: filedesc_to_refcount botch: fdl_refcount=0 cpuid = 1 Trace beginning at frame 0xfffff800ab95f728 fdfree() at fdfree+0x6f2 0xffffffff806331c2 fdfree() at fdfree+0x6f2 0xffffffff806331c2 exit1() at exit1+0x13f 0xffffffff8063ef6f sigexit() at sigexit+0x4c 0xffffffff8066091c postsig() at postsig+0x44a 0xffffffff8066173a userret() at userret+0x28b 0xffffffff80bd50bb Debugger("panic") CPU1 stopping CPUs: 0x00000001 stopped Stopped at Debugger+0x7c: movb $0,0xbd77f9(%rip) db> This is the exact KASSERT: sys/kern/kern_descrip.c:2627 KASSERT(fdtol->fdl_refcount > 0, sys/kern/kern_descrip.c:2628 ("filedesc_to_refcount botch: fdl_refcount=%d", sys/kern/kern_descrip.c:2629 fdtol->fdl_refcount)); firing with fdl_refcount=0 -- i.e. the decrement side drove the shared refcount word below the true reference count because a concurrent increment (kern_fork.c:569) was lost (the two sides hold different, non-mutual locks). -------------------------------------------------------------------------------- PANIC B -- slab double-free detection. After the premature kfree(fdtol) in fdfree, a peer's dangling p_fdtol reference caused a second free of the same M_FILEDESC_TO_LEADER object -> the slab allocator's BADFREE2 check fires. -------------------------------------------------------------------------------- login: panic: BADFREE2 cpuid = 0 Trace beginning at frame 0xfffff800ab92c6f8 _kfree() at _kfree+0x593 0xffffffff80657b23 _kfree() at _kfree+0x593 0xffffffff80657b23 sysctl_kern_proc_args() at sysctl_kern_proc_args+0x475 0xffffffff8064ebf5 sysctl_root.isra.5() at sysctl_root.isra.5+0x208 0xffffffff806834b8 userland_sysctl() at userland_sysctl+0x111 0xffffffff806837b1 sys___sysctl() at sys___sysctl+0x74 0xffffffff80683914 Debugger("panic") CPU0 stopping CPUs: 0x00000002 stopped Stopped at Debugger+0x7c: movb $0,0xbd77f9(%rip) db> (The sysctl_kern_proc_args frame is collateral: the UAF corrupted slab metadata of a neighboring allocation in the same zone; the slab's free-list bookkeeping became inconsistent, so a later kfree in an unrelated path trips BADFREE2.) -------------------------------------------------------------------------------- PANIC C (SMOKING GUN) -- slab corruption detected on the NEXT allocation out of the M_FILEDESC_TO_LEADER zone. The stack walks the EXACT functions cited in the finding: filedesc_to_leader_alloc <- fork1 <- sys_rfork. -------------------------------------------------------------------------------- login: panic: memory chunk 0xfffff800461052ad is already allocated! cpuid = 0 Trace beginning at frame 0xfffff800ab68b7c8 chunk_mark_allocated() at chunk_mark_allocated+0x9e 0xffffffff8065556e chunk_mark_allocated() at chunk_mark_allocated+0x9e 0xffffffff8065556e _kmalloc() at _kmalloc+0x684 0xffffffff80656b54 filedesc_to_leader_alloc() at filedesc_to_leader_alloc+0x23 0xffffffff80633e43 fork1() at fork1+0xbe9 0xffffffff80642be9 sys_rfork() at sys_rfork+0x43 0xffffffff80642d73 Debugger("panic") CPU0 stopping CPUs: 0x00000002 stopped Stopped at Debugger+0x7c: movb $0,0xbd77f9(%rip) db> This confirms the full chain end-to-end: 1. refcount race (kern_fork.c:569 ++ under p_token | kern_descrip.c:2675 -- under fd_spin) 2. premature kfree(fdtol) in fdfree (kern_descrip.c:2686) 3. dangling p_fdtol -> writes into the freed 64-byte-zone slot -> slab corruption 4. next filedesc_to_leader_alloc() (kern_descrip.c:3352) -> _kmalloc -> slab sees the corrupted chunk as "already allocated" -> panic