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