⬢ DragonFlyBSD Kernel Audit
DF-5512 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5512",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "REPRODUCED 4/4 pristine runs (deterministic rig test). ppbus_setup_intr() only checks bus ownership (ppbconf.c:416) and then unconditionally overwrites ppbdev->intr_cookie/intr_resource (:426-427) -- the very bookkeeping ppb_release_bus() relies on to force-unregister the childs handler at :514-521. A child that registers twice therefore orphans its first handler: the rig performs two BUS_SETUP_INTR calls on an owning child -- exactly what lpt.cs write-error paths produce (lpt.c:745-815 returns from lptwrite holding the bus with the handler registered; the next write re-registers) -- and the fake parent records 2 registrations while ppbus ivars hold only cookie #2; after ppb_release_bus() exactly one teardown happens and ONE handler remains live at the parent bus while ppbus believes none is registered (ivars cookie/resource NULL). Ceiling: handler count grows once per interrupted-write/print cycle (each parallel-port ACK then runs lpt_intr multiple times -> strobed byte-stream corruption) and the orphans persist until driver detach; requires an IRQ-mode parallel port, so hardware-gated. Fix validated: setup #2 now returns EBUSY(16), ppb_release_bus tears the single registration down (still-live=0), and lpt degrades safely to polled mode on EBUSY (lpt.c:754-757).",
  "exploit_chain": "",
  "evidence": "run.log (DF-5512 setup#2 err=0 ... after ppb_release_bus: parent setups=2 teardowns=1 still-live=1 ... REPRODUCED); fix_run.log (setup#2 err=16 ... still-live=0); harness.c hx_f3_intr_test; fix.diff hunk 2.",
  "kernel_refs": [
    "sys/bus/ppbus/ppbconf.c:426",
    "sys/bus/ppbus/ppbconf.c:415",
    "sys/bus/ppbus/ppbconf.c:514",
    "sys/dev/misc/lpt/lpt.c:745"
  ],
  "poc_changes": "No seed PoC existed (pass-2 finding); rig written from scratch following the DF-5418/5419 ppbharness class: verbatim-source KLD (ppbconf.c+ppb_1284.c+ppb_base.c), scripted IEEE1284 nibble-mode peer, fake ppc controller on nexus, real ppbus driver attach. Bring-up fixes: comment typo; the stack pre-dirtier initially collapsed to a single frame via -O2 tail-call optimization (made noinline with a post-call touch).",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 75,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (guest: cp harness.c Makefile /tmp/ppx2; make SYSDIR=/usr/src/sys)",
  "run_cmd": "kldload /tmp/ppx2/ppbharness2.ko; sleep 75; dmesg | grep PPBX2   (sh run.sh)",
  "code_hash": "eaa32f734c11c69696b7b680eca63a67cc24686475391b9b09cbd0c55c6be222",
  "notes": "ppc.cs setup_intr layer accepts chained handlers (shared IRQ support), so the duplicate registration succeeds in production; ppc_teardown_intr re-registers the default ppcintr on top, leaving both live.",
  "recommended_fix": "Refuse over-registration: if (ppbdev->intr_cookie != NULL) return (EBUSY) in ppbus_setup_intr (fix.diff hunk 2).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applied to the guests /usr/src/sys/bus/ppbus/ppbconf.c, harness rebuilt from the same verbatim source (module-level rebuild; running kernel unchanged), full rig re-run on a fresh boot: the previously observed bad behavior is GONE (setup#2 returns EBUSY and exactly one registration remains, which release tears down (still-live=0), verified on two patched boots). Behavior of the sibling known findings (DF-1093/2327/2328/2329) was not targeted by this diff.",
  "fix_evidence": "fix_run.log / fixrun2.dmesg (patched) vs run.log / run4.dmesg (pristine) in this pack; fix.diff is the exact applied diff.",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64"
}