⬢ DragonFlyBSD Kernel Audit
DF-5586 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5586",
  "status": "reproduced",
  "verdict": "exc_segfaults tail splz() (exception.c:270) dispatches deferred IPIs/interrupt work at the interrupted contexts critcount/nesting state, violating the dispatch protocol the real kernel enforces (pc64 doretis explicit TD_CRITCOUNT gate at ipl.s:143-146 and lwkt_maybe_splzs critcount==0/nesting==0/nest_count<2 guards at lwkt_thread.c:1091-1101); the vkernel splz (machintr.c:122-158) has no guards. Reproduced deterministically 3/3 in a faithful signal-structure model on the DragonFly guest: with the vkernels unguarded tail, the deferred IPI callback executes inside the interrupted critical section and observes/creates torn state (callback_critcount=1, callback_torn=1, INVARIANT_BROKEN lo=1/hi=2); with the pc64 doreti gate, dispatch is deferred to the crit_exit transition (callback_critcount=0, INVARIANT_OK). In the live vkernel the trigger needs a kernel-mode fault (guest-KVA demand VPTE install, or DDB single-step SIGTRAPs) to coincide with a held critical section and a deferred IPI \u2014 code-certain, frequency timing-dependent, so demonstrated in-vkernel impact is none; the in-vkernel fault storm (2000 guest-user faults + cross-CPU IPI churn on a 2-vCPU VKERNEL64) confirms normal guest-user fault storms never reach exc_segfault (they return via vmspace_ctl -> go_user -> user_trap), killing the pass-1 SA_NODEFER under fault storms concern, whose only deterministic recursion instance is already filed as DF-5338.",
  "reproduced": true,
  "impact": "none",
  "confidence": "likely",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-5586/build_and_model.log (3x model runs: vkernel mode INVARIANT_BROKEN callback_critcount=1 callback_torn=1 vs pc64 mode INVARIANT_OK callback_critcount=0); run_vk.log (in-vkernel storm STORM_DONE iters=500 intdiv=500 ill=500 prot=500 map=500, STORM_RC=0, vkernel ALIVE); fix validation: patched VKERNEL64 (fix.diff applied, rebuilt) passes the identical storm (STORM_RC=0, ALIVE) and pc64-mode model run demonstrates the guarded semantics; code divergence: exception.c:269-271 vs ipl.s:132-146, lwkt_thread.c:1068-1101, machintr.c:122-158",
  "kernel_refs": [
    "sys/platform/vkernel64/x86_64/exception.c:269",
    "sys/platform/vkernel64/platform/machintr.c:122",
    "sys/platform/pc64/x86_64/ipl.s:132",
    "sys/kern/lwkt_thread.c:1068",
    "sys/kern/lwkt_ipiq.c:727"
  ],
  "poc_changes": "Authored from scratch (no seed): faithful extraction of exception.cs dispatch structure (SA_NODEFER/empty-mask install, deferred-SIGUSR1 ipisig model, recoverable SIGSEGV via mmap-in-handler, splz tail) with a pc64-doreti-gate comparison mode; storm.c needed -O0 (gcc -O2 loop rotation misplaces &&label resume targets) and small iteration counts (~0.1ms per fault+sigreturn cycle); storm argv parsing order fixed; vkernel rig rebuilt from the DF-5556 recipe (DF-5474 link workaround, /var/vkernel dir required).",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 02:54:02 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 2400,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh (cc -static -O2 -o splzcrit splzcrit.c; cc -static -O0 -o storm storm.c); vkernel: make -j6 nativekernel KERNCONF=VKERNEL64 on the guest /usr/src (DF-5474 workaround)",
  "run_cmd": "./splzcrit vkernel; ./splzcrit pc64; in-vkernel: sh run_vk.sh (kernel.debug -m 512m -r /vkroot.img -n 2; /root/storm 500 1)",
  "code_hash": "d4cf6966c1b5e5f996e2c1adf92a43ac887db4dcd866c1fa23b3078fed28b20a",
  "notes": "memcorrupt bucket. The R10/R11 task-log lead does NOT live in this file: host signal frames fill all 25 regs (frame.h:57-83 == ucontext.h:50-74 verified field-by-field) and guest-user syscall frames bypass exception.c entirely; the real defect is pc64 exception.S Xfast_syscall (402-427) never storing TF_R10/TF_R11 \u2014 cross-file lead logged for exception.Ss own pass, vkernel-visible via vm_vmspace.c:882 copyout. SA_NODEFER/empty-sa_mask re-verified safe for the abandonment case: vkernel_lwp_exit handles killed-with-active-VC host-side without signals (vm_vmspace.c:815-840); pcb_onfault is dead in the vkernel (never set; copyio.c prefaults via vm_fault_page). Guest was heavily used (vkernel builds, storm rig, patched-src fix build) and reset with-src before return.",
  "recommended_fix": "Gate the tail splz() like doreti/lwkt_maybe_splz: only when curthread->td_critcount==0 && mycpu->gd_intr_nesting_level==0 && curthread->td_nest_count<2",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": true,
  "fix_verdict": "fix.diff applied to the guest /usr/src (combined with DF-5587s guard), VKERNEL64 rebuilt cleanly, identical in-vkernel fault storm passes (STORM_DONE, STORM_RC=0, ALIVE) \u2014 no regression; the guards dispatch semantics are exactly the pc64 mode of the model reproducer (callback_critcount=0, INVARIANT_OK, deferred to crit_exit).",
  "fix_evidence": "findings/poc/DF-5586/run_vk.log (baseline storm) + patched-vkernel run (STORM_RC=0 ALIVE) + build_and_model.log pc64-mode section; fix.diff"
}