⬢ DragonFlyBSD Kernel Audit
DF-2297 / verdict.json
← back to finding ↓ download raw
{
  "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)"
}