Any fault in a vkernel cothread dies silently through unbounded exc_segfault recursion: SA_NODEFER + empty sa_mask re-entry on a %gs==0 thread hits kern_trap's mycpu load and recurses ~308k times until the host kills the vkernel β no panic, no dump, no diagnostic
Summary
Fault handlers are installed process-wide with SA_NODEFER+empty sa_mask while cothreads run with %gs=0 and fault signals unmasked: a cothread fault enters exc_segfault whose first kern_trap statement (mycpu load) immediately re-faults and re-delivers without bound - measured 307,833 re-entries 3/3 before silent host kill, no core path through the guest panic machinery (vs the real kernel's #DF -> dblfault_handler -> panic). Crash-diagnostics loss, latent (needs a cothread-side driver bug). exc_nesting guard + honest-death fix validated in the model and built into the guest VKERNEL64.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5587 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| coresig.c | β | 3.8 KB | view raw | |
| corefixed.c | β | 2.1 KB | view raw | |
| build.sh | β | 107 B | view raw | |
| run.sh | β | 103 B | view raw | |
| build_and_run.log | β | 736 B | view raw | |
| fix_semantics.log | β | 192 B | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| VERDICT.md | β | 3.3 KB | β raw | |
| README.md | β | 1.1 KB | β raw | |
| verdict.json | β | 3.7 KB | view raw | |
| manifest.json | β | 1.0 KB | view raw | |
| env.txt | β | 526 B | view raw |
DF-5587 β PoC pack
Build (on the DragonFly guest)
sh build.sh # cc -static -O2 -o coresig coresig.c cc -static -O2 -o corefixed corefixed.c # fix-semantics demo
Run
./coresig # baseline: silent unbounded recursion death ./corefixed # with fix.diff guard semantics
Expected (baseline, 3/3 deterministic):
child wait status: exited=0 exit=-1 signaled=1 termsig=4 core=128 RECURSION_DEPTH=307833 SILENT_DEATH_CONFIRMED: ... RC=0
Expected (fix semantics):
vkernel: recursive fault in exc_segfault child: signaled=1 termsig=11 core=128 handler_entries=2 FIX_SEMANTICS_OK: honest SIGSEGV death after 2 entries with diagnostic RC=0
Files
coresig.cβ baseline reproducer (exact init_exceptions install flags)corefixed.cβ fix-semantics demo (exc_nesting guard)build.sh/run.shbuild_and_run.logβ full build + 3Γ runs (untrimmed)fix_semantics.logβ corefixed runfix.diffβ exc_segfault re-entrancy guard + honest deathverdict.json,manifest.json,VERDICT.md
DF-5587 β cothread faults die silently through unbounded exc_segfault recursion (SA_NODEFER + empty sa_mask + %gs==0)
What
init_exceptions() (sys/platform/vkernel64/x86_64/exception.c:222-229)
installs exc_segfault for SIGBUS/SIGSEGV/SIGTRAP/SIGFPE process-wide with
SA_SIGINFO | SA_NODEFER and an empty sa_mask. The vkernel's
cothreads run with:
%gs = 0(tls_set_gs(0, ...),sys/platform/vkernel64/platform/cothread.c:143-148β "%gs (aka mycpu) is illegal in cothreads"), and- only the 8 interrupt signals masked
(
cpu_mask_all_signals(),sys/platform/vkernel64/platform/machintr.c:205-211β SIGSEGV/SIGBUS/SIGTRAP/SIGFPE are NOT in the set).
So any fault in any cothread (disk/net/console I/O threads executing
guest-issued requests) is delivered to exc_segfault, whose first real
work is kern_trap() β whose first statement is
struct globaldata *gd = mycpu; (trap.c:585) β a %gs-relative load
that faults when %gs==0. With SA_NODEFER and an empty mask the signal
is re-delivered immediately on the same stack: unbounded recursion, no
nesting guard, no SA_ONSTACK, until the host cannot push the signal frame
and kills the whole vkernel process β no panic, no dump path, no
diagnostic (a real kernel turns this class into #DF β dblfault_handler
β panic with register state, trap.c:969-997).
Latent trigger (requires a cothread-side fault, i.e. a vkernel driver bug or bad DMA pointer): severity Info / hardening. The sibling deterministic recursion for lwkt threads with a valid %gs is DF-5338 (trap.c fall-through); this one never even reaches trap.c's switch.
Reproducer
coresig.c β installs the exact init_exceptions signal configuration
(SA_SIGINFO|SA_NODEFER, empty mask) and a handler whose first dereference
uses a NULL "%gs base" (the cothread condition), then takes one fault.
Result on the DragonFly guest (3/3 deterministic):
child wait status: exited=0 exit=-1 signaled=1 termsig=4 core=128 RECURSION_DEPTH=307833 SILENT_DEATH_CONFIRMED: handler re-entered 307833 times before the host killed the process β no panic, no dump path, no diagnostic
corefixed.c β fix-semantics demo (the exc_nesting guard from
fix.diff): the recursion is caught at depth 2, one diagnostic line is
printed, the disposition is reset to SIG_DFL, and the child dies of the
true faulting signal (SIGSEGV, core dumped) after exactly 2 handler
entries.
Fix
fix.diff β re-entrancy guard + honest death (diagnostic, SIG_DFL,
re-raise) in exc_segfault. Applied together with DF-5586's guard on the
guest's /usr/src; VKERNEL64 rebuilt cleanly (build+link OK) and the
in-vkernel fault storm still passes (STORM_RC=0, ALIVE).
Verdict summary
- status: reproduced (mechanism: 307,833 silent re-entries β host kill, 3/3; fix semantics: 2 entries + diagnostic + true SIGSEGV)
- impact: dos-class within the VM (whole-vkernel death, silent), but latent (needs a cothread fault to fire); severity Info, confidence certain (mechanism), trigger speculative.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedfix.diff guard semantics proven by corefixed (2 entries + diagnostic + true SIGSEGV vs 307833 silent); applied (combined with DF-5586's guard) to guest /usr/src, VKERNEL64 rebuilt cleanly, in-vkernel fault storm passes unchanged (STORM_RC=0, ALIVE).
findings/poc/DF-5587/fix_semantics.log; findings/poc/DF-5586/run_vk.log (patched-vkernel storm); fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-5587/build_and_run.log (3x: RECURSION_DEPTH=307833, SILENT_DEATH_CONFIRMED, termsig=4 core=128); fix_semantics.log (corefixed: 'vkernel: recursive fault in exc_segfault', termsig=11, handler_entries=2, FIX_SEMANTICS_OK); code: exception.c:222-229 + cothread.c:143-148 (tls_set_gs(0)) + machintr.c:205-211 (fault signals unmasked) + trap.c:585 (mycpu first)
PoC changes
Authored from scratch (no seed): exact init_exceptions install flags + NULL 'TLS base' first dereference (the %gs==0 condition); shared MAP_ANON page for the cross-fork recursion counter; corefixed.c needed the shared-page counter too (COW hid the depth in the parent).
Verified recommended fix
exc_segfault re-entrancy guard: exc_nesting counter; on re-entry write(2) a diagnostic, reset the four fault dispositions to SIG_DFL and raise(signo) for an honest, core-dumping death
Verdict
exc_segfault is installed process-wide with SA_SIGINFO|SA_NODEFER and an empty sa_mask (exception.c:222-229); the vkernel's cothreads run with %gs=0 (tls_set_gs(0), cothread.c:143-148) and only the 8 interrupt signals masked (cpu_mask_all_signals, machintr.c:205-211) β so any cothread fault enters exc_segfault whose kern_trap first statement (mycpu, trap.c:585) immediately re-faults, and SA_NODEFER+empty-mask re-delivers on the same stack without bound: measured 307,833 handler re-entries (3/3 deterministic) before the host killed the process (SIGILL/core on delivery failure) β the whole vkernel dies with no panic, no dump path, no diagnostic, versus the real kernel's #DF->dblfault_handler->panic. Latent trigger (requires a cothread-side fault, e.g. a vkernel driver bug or bad DMA pointer in a disk/net/console cothread executing guest-issued I/O), so severity Info/hardening; the deterministic lwkt-thread recursion instance of the same install is DF-5338 (trap.c fall-through root). Fix semantics demonstrated: the exc_nesting guard from fix.diff converts the death to a one-line diagnostic + true SIGSEGV with core after exactly 2 handler entries; guard applied (combined with DF-5586's) into the guest /usr/src, VKERNEL64 rebuilt cleanly, in-vkernel fault storm still passes.
No comments yet.