⬢ DragonFlyBSD Kernel Audit
DF-2302 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2302",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Kernel panic through 100% real code: with the sub-4MB 32-bit DMA bounce window exhausted (rig models the >4GB-RAM host where the stock fwohci tag lowaddr=32BIT must bounce), the REAL fwohci_db_init loop hit a REAL bus_dmamap_create failure (alloc_bounce_pages -> contigmalloc -> NULL, busdma_machdep.c:412), printed bus_dmamap_create failed (fwohci.c:1237), faked FWOHCI_DBCH_INIT (fwohci.c:1238) and called fwohci_db_free, whose unguarded loop (fwohci.c:1166-1167, idb < ndb over a K-entry queue) dereferenced NULL: Fatal trap 12, fault VA 0x18 = offsetof(fwohcidb_tr, dma_map), backtrace fwohci_db_free <- db_init <- ioctl (panic.txt). New line-accurate knowledge: DF busdma clears later map_create failures once MIN_ALLOC_COMP is set (busdma_machdep.c:423-425 error=0), so the reachable form on this tree is K=0 (empty queue, fault at iteration 0); the K>0 partial-queue form is masked today but is the same defect and re-arms with any busdma change. Fix (NULL-safe loop + tail kfree guard) validated A/B: the patched kernel took the identical bus_dmamap_create-failed path repeatedly and unwound cleanly every time.",
  "exploit_chain": "memory pressure in the 32-bit DMA window (unpriv users can generate it) + FireWire channel init (operator group) -> bus_dmamap_create ENOMEM inside fwohci_db_init -> fake flag + fwohci_db_free -> NULL deref -> fatal trap 12 -> kernel panic (local DoS). No escalation path: NULL dereference only.",
  "evidence": "panic.txt: bus_dmamap_create failed then Fatal trap 12 fault VA 0x18 with fwohci_db_free in the trace, after ate=0/freed=0 window exhaustion; run.log: the 57-round conditioning history (ate 128 -> 0, each round converting 1-2 window pages into permanent zone bounce pages); run_fixed.log: 41 conditioning rounds + 5 terminal rounds on the patched kernel, bus_dmamap_create failed observed twice, every round survived, ctl state shows flags=0 (clean unwind)",
  "kernel_refs": ["sys/bus/firewire/fwohci.c:1229", "sys/bus/firewire/fwohci.c:1236", "sys/bus/firewire/fwohci.c:1238", "sys/bus/firewire/fwohci.c:1157", "sys/bus/firewire/fwohci.c:1166", "sys/bus/firewire/fwohcireg.h:330", "sys/platform/pc64/x86_64/busdma_machdep.c:359", "sys/platform/pc64/x86_64/busdma_machdep.c:412", "sys/platform/pc64/x86_64/busdma_machdep.c:423", "sys/vm/vm_contig.c:560"],
  "poc_changes": "Rig FWOIOC_MEMEAT: contigmalloc(M_WAITOK) eater pins the whole [0,4MB) window with the same 3-pass reclamation power as the busdma path, frees F pages, then runs the real fwohci_db_init; a 4MB-lowaddr fabricated parent tag models the >4GB host. Initial NOWAIT eater and small F values failed to trigger because the first map_create can reclaim cache/active pages; the WORKING sequence is repeated rounds (each permanently converts window pages into zone bounce pages) until ate=0, then the terminal rounds fail map_create deterministically.",
  "attempts": 9,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #4: Sun Oct 18 12:45:22 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/FWO  x86_64",
  "runtime_sec": 2700,
  "guest_dirty": 0,
  "build_cmd": "cd /usr/src && make -j6 nativekernel KERNCONF=FWO && make installkernel KERNCONF=FWO (userland: cc -O -Wall -o fwpoc fwpoc.c)",
  "run_cmd": "sh /root/fwo/run2302.sh 2  (repeat rounds until ate=0; panic occurs on the terminal round)",
  "code_hash": "32c9c567b4185994d7189b0afb68d72d9d4a3d1c02bdd62424d762a660ee24fd",
  "notes": "K=0 is the reachable form on DF 6.5 (busdma error=0 quirk masks later failures); the filed K>0 form is the same loop defect. The first authored fix (loop guard only) would have traded the panic for kfree(NULL) (kern_slaballoc.c:1409 panics on NULL) - caught while authoring; fix.diff guards both. Residual: the K=0 error path leaks one db_tr array (db_init loses the base pointer across the loop); fixing that cleanly needs an array-head local in db_init and was left out to keep the patch minimal.",
  "recommended_fix": "NULL-safe loop condition (db_tr != NULL && idb < dbch->ndb) plus guard the tail kfree(STAILQ_FIRST(...)) (fix.diff)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #4: Sun Oct 18 12:45:22 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/FWO x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Patched kernel: full conditioning replicated from a fresh boot (41 rounds to window exhaustion), the bus_dmamap_create failed message observed twice in dmesg (the exact failure that panicked the baseline), every round returned survived=1, channel state flags=0 (fwohci_db_free completed cleanly), guest up throughout.",
  "fix_evidence": "run_fixed.log: rounds 1..41 with ate declining 128->0 then terminal rounds; dmesg: 2x bus_dmamap_create failed + db_init RETURNED flags=0; ctl state 3: flags=0 ndb=64 top=1"
}