DF-2297 / verdict.json
{ "finding_id": "DF-2297", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED on the QEMU guest with the unmodified production firewire.c+fwdma.c+fwdev.c compiled into KLD df229x.ko (DF-5613 pattern), driving the real FW_SSTBUF/FW_STSTREAM ioctl path. FW_SSTBUF (fwdev.c:504-506) copies userspace ints with no validation; roundup2(psize,4) leaves 0 as 0 and 0x80000000 as 0x80000000; fwdev.c:108-109 passes psize as esize to fwdma_malloc_multiseg, which divides by it with no check. psize=0 -> Fatal trap 18 (integer divide fault), Stopped at dfw_dma_malloc_multiseg+0x139: idivl (fwdma.c:159 rounddown(PAGE_SIZE,0)); psize=0x80000000 (INT_MIN esize -> ssize=0) -> same fatal trap at +0x153: divq (fwdma.c:160 howmany(n, ssize/esize=0)). Both variants killed the guest in DDB on first fire. Reachable today from any user with /dev/fwU.S open (0660 root:operator). Pass-2 had merely declined to re-file (same crash site), not claimed unreachability -- this run confirms the claim on current production code.", "exploit_chain": "open /dev/fw0.0 (operator group) -> ioctl(FW_SSTBUF, {psize=0 or >=0x80000000}) -> ioctl(FW_STSTREAM) -> fwdev_allocbuf -> fwdma_malloc_multiseg(esize=0|INT_MIN) -> kernel-mode integer-divide fault -> immediate system-wide panic/DoS. No memory-corruption escalation on this path (trap precedes any allocation use).", "evidence": "panic.txt (psize=0: Fatal trap 18: integer divide fault while in kernel mode ... Stopped at dfw_dma_malloc_multiseg+0x139: idivl %esi,%eax), panic_psize80000000.txt + run_variantB.log (INT_MIN variant: +0x153: divq %rsi,%eax -- the second, distinct division site), run.log (baseline trail: SSTBUF err=0 then the trap), fix_run.log (patched: DF-2297 t3 psize=0x0: STSTREAM err=22, no trap, t1 psize=0x80000000: err=22, guard: esize=0 -> 0, esize<0 -> 0, n=0 -> 0 (no trap), regression OK), baseline_build.log / fix_build.log (clean builds of unmodified/patched production sources), env.txt", "kernel_refs": [ "sys/bus/firewire/fwdma.c:145", "sys/bus/firewire/fwdma.c:153", "sys/bus/firewire/fwdma.c:159", "sys/bus/firewire/fwdma.c:160", "sys/bus/firewire/fwdev.c:107", "sys/bus/firewire/fwdev.c:108", "sys/bus/firewire/fwdev.c:458", "sys/bus/firewire/fwdev.c:486", "sys/bus/firewire/fwdev.c:504", "sys/bus/firewire/firewire.h:50", "sys/sys/param.h:396", "sys/sys/param.h:400" ], "poc_changes": "No seed existed (poc_path was empty). Harness df229x.c written fresh on the DF-5613/DF-5413 KLD pattern (production firewire.c+fwdma.c+fwdev.c #included with -D-renamed globals; synthetic fc/queues/cdevs): tests 1/3 fire the production SSTBUF+STSTREAM pair with psize=0x80000000/0; test 6 probes the fwdma guard directly; test 5 is a legit-config regression guard for fix validation.", "attempts": 2, "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": 4800, "guest_dirty": 0, "build_cmd": "sh build.sh (cd /root/df229x && make; compiles the unmodified production firewire.c+fwdma.c+fwdev.c into df229x.ko)", "run_cmd": "kldload /root/df229x/df229x.ko; sysctl kern.df229x_test=3 (psize=0 -> Fatal trap 18); after reset+redeploy+rebuild: sysctl kern.df229x_test=1 (psize=0x80000000 -> Fatal trap 18); fix validation: apply fix.diff to /usr/src, rebuild module, sh run_fix.sh", "code_hash": "6a11c862c5cec3c0fc16c7e8f2e39fc09c8ea7b46792cb29a2cdc98fd00f2e4a", "notes": "Reconciled against the pass-2 negative note: pass 2 only declined to re-file the negative-esize variant as a new finding (same crash site/class as DF-2297); both variants are in fact reachable and were reproduced on current production code. DF-2297 is the crash-site owner per the findings own summary (chain also noted by pass-1 DF-2293 against fwdev.c). DragonFly prints the x86 #DE (vector 0) as Fatal trap 18: integer divide fault. The panic kills the machine before DDB on default configs -- pure DoS.", "recommended_fix": "Validate in fwdma_malloc_multiseg (hard boundary: reject esize<=0 || n<=0 -> NULL) and in fwdev_allocbuf (EINVAL for psize==0, psize>0x7fffffff, nchunk==0, npacket==0, or npacket > 0x7fffffff/nchunk) -- fix.diff in this pack.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff (fwdma.c esize/n guard + fwdev.c fwdev_allocbuf validation) applied to the guest /usr/src; harness module rebuilt from the patched production sources. Baseline: both variants = Fatal trap 18, guest dead in DDB. Patched: psize=0 and psize=0x80000000 both return err=22 (EINVAL) with no trap; direct fwdma_malloc_multiseg(esize=0/-4096/n=0) probes return NULL; the legit {4,8,2048} config still allocates and streams; guest alive after the full suite.", "fix_evidence": "fix_run.log (full patched suite: t3/t1 err=22 no trap, t4/t2 rejected, t5 regression OK, t6 guard NULLs, guest still alive), fix_build.log (patched build), fix.diff (git apply --check verified against the repo sys/ tree; patch(1) applied cleanly to guest /usr/src)" } |