⬢ DragonFlyBSD Kernel Audit
DF-5303 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5303",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "DUMPDMAs channel bound check uses <= against OHCI_MAX_DMA_CH (0x44, a count), so ch==0x44 is accepted (fwohci.c:372); dump_db then computes dbch=&sc->ir[0x20] - one past ir[OHCI_DMA_IRCH] (fwohci.c:2261-2263) - which type-confuses the fwohci_softc tail (ndb==maxrec is always non-zero after reset per fwohci.c:521; top==sid_dma.dma_map), and the descriptor walk (fwohci.c:2275-2303) follows those fields as fwohcidb_tr pointers, printing or faulting on kernel heap internals; dump_dma sibling reads MMIO at 0x800 past the 2KB register file (fwohci.c:2203-2206). Reproduced on the guest: production dump_db(sc,0x44) with the aliased tail fields shaped as post-init state faulted at 0x10 in dump_db+0x58 (STAILQ_NEXT). Hardware-gated for the ioctl entry (no FW controller: fwohci_ioctls devclass lookup fails first), so the walk was driven directly; static chain from the ioctl is exact.",
  "exploit_chain": "operator-group user on a machine with a FireWire controller: open /dev/fwN.M -> ioctl(DUMPDMA, ch=0x44) -> dump_dma reads MMIO past the register file + dump_db walks a phantom ring built from softc-tail fields -> kernel panic (DoS) or print_db leaks kernel heap contents to console/log.",
  "evidence": "panic.txt: fault virtual address = 0x10 / supervisor read data / Stopped at dump_db+0x58: movq (%rax),%r9; panic.first.txt (earlier alias shape, fault in the No-DB device_printf branch); run.log; VERDICT.md has the phantom-field alias table.",
  "kernel_refs": [
    "sys/bus/firewire/fwohci.c:372",
    "sys/bus/firewire/fwohci.c:2261",
    "sys/bus/firewire/fwohci.c:2275",
    "sys/bus/firewire/fwohcireg.h:88"
  ],
  "poc_changes": "No seed PoC. Case 2 of the DF-5302 harness (kern.df5302_mode=2): calls the production dump_db(sc, OHCI_MAX_DMA_CH) with softc tail fields shaped like the post-fwohci_init state (maxrec=10, sid_dma.dma_map=0x10). Two earlier craft iterations mis-identified which tail field lands under phantom->top (STAILQ_HEAD is 16 bytes) - panic.first.txt preserves the first variant.",
  "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": 180,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (shared df5302.ko module build)",
  "run_cmd": "sh run.sh   (kldload /root/df5302/df5302.ko; sysctl kern.df5302_mode=2; sysctl kern.df5302_fire=1)",
  "code_hash": "ee628ed09368d18b165aea6b2d04ee98a12d4a42694566a15bb694391e216528",
  "notes": "Distinct from known DF-1006/DF-2301 (print_db loop off-by-one) and DF-2300 (missing privilege check): this is the ioctl channel-bound off-by-one feeding an OOB ir[] index in dump_db/dump_dma.",
  "recommended_fix": "Change the DUMPDMA bound to *dmach < OHCI_MAX_DMA_CH (see fix.diff); ideally also range-check IT/IR channels against the probed nisodma.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Baseline walk panic reproduced. The one-character bound fix (<= -> <) is provably correct by inspection (valid indices 0..0x43) and compiled cleanly in the fixed-module build of the DF-5302 cycle (applied at fwohci.c:372), but the ioctl entry cannot be driven end-to-end on this guest because fwohci_ioctls devclass_get_softc(firewire_devclass, unit) needs a real FireWire device - hence not_testable rather than fixed.",
  "fix_evidence": "fix.diff; DF-5302/fix_build.log (patch applied at fwohci.c:372 during the combined fixed build)."
}