DF-0017 / panic.txt
============================================================
DF-0017 — kernel panic signature (from dfbsd-qemu/boot.log)
Trigger: ./trigger 300 (300-deep DMSG circuit chain + root DELETE)
Guest: DragonFly v6.5.0.1712.g89e6a-DEVELOPMENT (X86_64_GENERIC)
============================================================
(Reproduced twice — identical signature, only the exhausted-stack
address differs between runs. rsp is page-aligned in both cases,
indicating total 16 KB LWKT thread-stack exhaustion.)
Run #1 (depth=300):
login: DOUBLE FAULT
Fatal double fault
rip = 0xffffffff806564d4
rsp = 0xfffff800abae1000
rbp = 0xfffff800abae1000
cpuid = 1; lapic id = 1
panic: double fault
cpuid = 1
Trace beginning at frame 0xfffff8004602eec8
dblfault_handler() at dblfault_handler+0x10c 0xffffffff80bd5f3c
dblfault_handler() at dblfault_handler+0x10c 0xffffffff80bd5f3c
Debugger("panic")
CPU1 stopping CPUs: 0x00000001
stopped
Stopped at Debugger+0x7c: movb $0,0xbd77f9(%rip)
db>
------------------------------------------------------------
Run #2 (depth=300, after control run depth=5 which did NOT panic):
login: DOUBLE FAULT
Fatal double fault
rip = 0xffffffff806564d4
rsp = 0xfffff800ab38f000
rbp = 0xfffff800ab38f000
cpuid = 1; lapic id = 1
panic: double fault
cpuid = 1
Trace beginning at frame 0xfffff8004602eec8
dblfault_handler() at dblfault_handler+0x10c 0xffffffff80bd5f3c
dblfault_handler() at dblfault_handler+0x10c 0xffffffff80bd5f3c
Debugger("panic")
CPU1 stopping CPUs: 0x00000001
stopped
Stopped at Debugger+0x7c: movb $0,0xbd77f9(%rip)
db>
------------------------------------------------------------
INTERPRETATION
------------------------------------------------------------
A "Fatal double fault" with a page-aligned rsp (== rbp) is the
canonical signature of a kernel thread stack overflow on x86: the
unbounded recursion exhausts the 16 KB LWKT kernel thread stack
(LWKT_THREAD_STACK = UPAGES*PAGE_SIZE = 4*4096, sys/sys/thread.h:472),
the stack pointer runs off the allocation, and the next push/fault
finds no usable stack to dispatch even a normal page-fault handler ->
double fault -> panic.
The double-fault trace naturally shows only dblfault_handler() because
the original (kdmsg) call frames have been destroyed by the stack
exhaustion -- there is no recoverable frame to walk. (Confirmed: the
LWKT stack has NO guard page; kmem_alloc_stack() in sys/vm/vm_extern.h
is just kmem_alloc1(..|KM_STACK) with no guard mapping, so the overflow
corrupts adjacent kernel memory before double-faulting -- i.e. it is a
memory-corruption primitive that reliably manifests as a DoS.)
The chain is built by the DMSG CREATE/circuit-nesting path and torn
down by kdmsg_simulate_failure() / kdmsg_state_dying(), both unbounded
recursive walks (sys/kern/kern_dmsg.c:1346 and :1428). See VERDICT.md.