DF-5512 / verdict.json
{ "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" } |