DF-0725 / panic.txt
DF-0725 if_clone_destroy UAF / double-free-unit race — panic signature
======================================================================
Guest: DragonFly 6.5-DEVELOPMENT #0 (unpatched audit-source, X86_64_GENERIC, INVARIANTS ON)
Trigger: ./race_destroy 12 5000 (12 root processes racing SIOCIFDESTROY gif666)
Mechanism: two concurrent if_clone_destroy() callers both pass ifunit() with the
same live ifp (ifnet_lock dropped at if_clone.c:112 before the ifp->if_dname
deref at :116), then both enter the lock-protected critical section at :126.
The second one's if_clone_free_unit() re-clears an already-cleared bitmap bit
-> KKASSERT "bit is already cleared" (if_clone.c:367-368) -> panic.
Serial console (dfbsd-qemu/boot.log):
panic: if_clone_free_unit: bit is already cleared
cpuid = 5
Trace beginning at frame 0xfffff801186a9768
if_clone_free_unit.isra.1() at if_clone_free_unit.isra.1+0x49 0xffffffff80733f29
if_clone_free_unit.isra.1() at if_clone_free_unit.isra.1+0x49 0xffffffff80733f29
if_clone_destroy() at if_clone_destroy+0x7c 0xffffffff807341fc
ifioctl() at ifioctl+0x243 0xffffffff80731d73
mapped_ioctl() at mapped_ioctl+0x5fa 0xffffffff806a831a
syscall2() at syscall2+0x11e 0xffffffff80bd6a0e
Debugger("panic")
CPU5 stopping CPUs: 0x0000001f
stopped
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
Interpretation:
- With INVARIANTS ON (default GENERIC): the KKASSERT at if_clone.c:367 fires on the
second destroyer's redundant unit-bit clear -> deterministic panic (this trace).
- With INVARIANTS OFF: the second destroyer proceeds to ifc->ifc_destroy(ifp) at
:128 on the ifp that the first destroyer already freed (gif_clone_destroy -> if_detach
-> kfree ifp) -> use-after-free (silent heap corruption / secondary panic).
Reachability: SIOCIFDESTROY is gated by caps_priv_check(SYSCAP_RESTRICTEDROOT)
(sys/net/if.c:2013); tun/tap auto-destroy-on-close is also root-gated
(tunopen:283, tapopen:324 both require SYSCAP_RESTRICTEDROOT). So the race is
root-triggerable only -> root->kernel DoS / hardening gap (no unpriv path).