DF-2301 / verdict.json
{ "finding_id": "DF-2301", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "print_db (fwohci.c:2322-2404) driven by an operator-group DUMPDMA(0) through the real fwohci_ioctl/dump_dma/dump_db path printed ndesc+1 = 9 rows for an 8-descriptor block: row i==8 read db[8], one 16-byte struct fwohcidb past the block. Attribution is byte-exact: (a) with the match on element 5, row 8 printed exactly the canary planted in element 6 db[0] (KVA 0xfffff80117c14300, rig KVA peek returns the same cafe0001/11111111/22222222/33333333), and the canary cmd key bits also fired the compounding db[i+1] ST2 read (fwohci.c:2377-2382, printing db[9]); (b) with the match on element 63 (last element of the last 4096-byte fwdma segment), row 8 read at seglast.v_addr+4096 - outside every segment allocation - matching the KVA peek of that address. Output goes to console/dmesg (world-readable): kernel DMA-memory disclosure; latent fault if the read ever lands unmapped.", "exploit_chain": "operator-group user -> DUMPDMA(0) on /dev/fw0.0 -> fwohci_ioctl (fwohci.c:371) -> dump_db (max=ndesc, fwohci.c:2311) -> print_db loop i<=max (fwohci.c:2347) reads db[ndesc] (and db[i+1] for ST2 keys) -> 16+ bytes past the descriptor block printed to console/dmesg", "evidence": "run.log: two print_db dumps with 9 rows each; element-5 dump row 8 = canary values matching CTL_KREAD of &db[8]; element-63 dump row 8 = values at seg1+4096 matching CTL_KREAD of the same out-of-allocation address; run_fixed.log: patched kernel prints exactly 8 rows, no OOB row", "kernel_refs": ["sys/bus/firewire/fwohci.c:2322", "sys/bus/firewire/fwohci.c:2347", "sys/bus/firewire/fwohci.c:2377", "sys/bus/firewire/fwohci.c:2379", "sys/bus/firewire/fwohci.c:2400", "sys/bus/firewire/fwohci.c:2311", "sys/bus/firewire/fwdma.c:145"], "poc_changes": "Rig prep (fwohci_harness.c FWOIOC_DBINIT/DESCSET/REGWR/KREAD): real fwohci_db_init on atrq with ndesc=8 ndb=64 (2 fwdma segments, 32 elements each), fabricated INPUT_MORE|KEY_ST3 descriptors that avoid all early-exit conditions so the loop runs to exhaustion, canary in element 6, ATQ command-pointer register set in emulated MMIO so dump_db matches the chosen element; trigger issued by opuser as /home/opuser/fwpoc dumpdma 0.", "attempts": 3, "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": 600, "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/run2301.sh", "code_hash": "32c9c567b4185994d7189b0afb68d72d9d4a3d1c02bdd62424d762a660ee24fd", "notes": "Read-only OOB; disclosure surface is console/dmesg, not copyout. Severity Low as filed. The ST2 compounding read (db[i+1] at i==max-1... also covered by the fix guard) was demonstrated live when the canary cmd accidentally carried ST2 key bits.", "recommended_fix": "Loop bound i<max plus guard the ST2 immediate print with i+1<max (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: identical prep and DUMPDMA print exactly ndesc=8 rows with no ninth row, no canary row, and no ST2 compounding line (run_fixed.log). Note the combined fix also gates DUMPDMA behind the privilege check, so the A/B dump was issued by root; opuser DUMPDMA produced no print_db output at all on the patched kernel.", "fix_evidence": "run_fixed.log DF-2301 section: opuser DUMPDMA prints nothing (gate), root DUMPDMA prints 8 rows ending at i==7 (aa000007/bb000007) with no further row" } |