{
  "finding_id": "DF-5613",
  "status": "reproduced",
  "reproduced": true,
  "impact": "memcorrupt: controlled kernel UAF write (attacker iso payload into fwdma segment pages freed by the concurrent teardown) + linear heap overflow past the bulkxfer kmalloc with chosen poffset ints; fatal supervisor-write variant on >=4GB-RAM hosts (panic.txt)",
  "confidence": "certain",
  "verdict": "Reproduced on the QEMU guest with the unmodified production firewire.c+fwdma.c+fwdev.c compiled into KLD df5613.ko (DF-5413 pattern). Test 1: two fds racing the unsynchronized FW_STSTREAM claim both own one fw_xferq (d1->it == d2->it); the winners chunk loop (fwdev.c:126-130) then wrote 64 fw_bulkxfer entries through the losers 2-entry 64-byte kmalloc -- 62/62 out-of-bounds entries carried the attacker-chosen poffset=i*npacket pattern (1984-byte heap overflow). Test 2: from that shared-queue state, fd1s production fw_close -> fwdev_freebuf -> fwdma_free_multiseg (fwdma.c:207-218) freed the segment pages under fd2s in-flight fw_write; after spray reclamation of the freed 4096-byte segment page, fd2s uiomove (fwdev.c:390-392) wrote 2048 bytes of attacker iso payload into the reclaimed page (DF5613-UAF found in spray block 15) -- UAF write with controlled content. On a 4GB-RAM guest the same race taken mid-flight by pure production code faulted writing the stale segment pointer: Fatal trap 12, supervisor write, in fw_writes memmove (panic.txt). fix.diff (atomic claim under crit + freebuf list/stproc cleanup + loop-top rechecks) validated: patched run shows OPEN set before the sleeping allocation, fd2 claims a different queue, shared=no overflow=0.",
  "exploit_chain": "open /dev/fw0.0 + /dev/fw0.1 (operator group) -> race FW_SSTBUF+FW_STSTREAM claims (window = fwdma_malloc_multiseg, widened at will via nchunk*npacket) -> shared fw_xferq -> (a) bulkxfer heap overflow: nchunk*32 bytes past a kmalloc with poffset=i*npacket chosen ints + STAILQ link pointers, or (b) close-vs-write UAF: fwdma_v_addr (fwdma.h:59-66) reads am->seg[] and returns pointers into freed segment pages; spray-reclaim the 4096-byte kmalloc zone; each fw_write packet uiomoves up to 64KB (stream.len:16, attacker-set) of chosen bytes into the reclaimed objects -> overwrite reallocated kernel object (function pointer / cred-adjacent) -> uid=0 on the no-SMAP/SMEP/KASLR guest. Full uid=0 chain not constructed (entry hardware-gated in QEMU: /dev/fw* needs an attached OHCI), same evidence-class standard as DF-5413/DF-5548.",
  "evidence": "run.log (test 2: UAF WRITE landed in spray block 15 ... at offset 11, context \"....13-UAF!DF5613-UAF!DF5613-UAF\", len=42432 read from the reclaimed page; test 1: shared=YES, q->bulkxfer[8].poffset = 512 ... [20] = 1280, 62 of 62 ... heap overflow CONFIRMED), panic.txt (4GB run: Fatal trap 12 supervisor write in memmove via production fw_write on the freed segment pointer), fix_run.log (OPEN=1 inside fwdma_malloc_multiseg, d2->it != fc.it[0], shared=no overflow=0), build.log/fix_build.log, env.txt",
  "kernel_refs": [
    "sys/bus/firewire/fwdev.c:100",
    "sys/bus/firewire/fwdev.c:103",
    "sys/bus/firewire/fwdev.c:108",
    "sys/bus/firewire/fwdev.c:126",
    "sys/bus/firewire/fwdev.c:139",
    "sys/bus/firewire/fwdev.c:144",
    "sys/bus/firewire/fwdev.c:366",
    "sys/bus/firewire/fwdev.c:388",
    "sys/bus/firewire/fwdev.c:447",
    "sys/bus/firewire/fwdev.c:461",
    "sys/bus/firewire/fwdev.c:475",
    "sys/bus/firewire/fwdev.c:489",
    "sys/bus/firewire/fwdma.c:144",
    "sys/bus/firewire/fwdma.c:193",
    "sys/bus/firewire/fwdma.c:207",
    "sys/bus/firewire/fwdma.h:59",
    "sys/platform/pc64/x86_64/busdma_machdep.c:88"
  ],
  "poc_changes": "Harness written fresh on the DF-5413 KLD pattern (production firewire.c+fwdma.c+fwdev.c #included with -D-renamed globals, synthetic fc/devclass/cdevs): test 1 races two STSTREAM claims (poll for q->bulkxfer set && q->buf NULL to pin fd1 inside fwdma_malloc_multiseg), test 2 occupies the proven loser-thread interleaving (cached fwdma_v_addr element pointer across production fw_close, then the fwdev.c:390-392 uiomoves into spray-reclaimed segment pages). Two earlier fully-threaded test-2 designs were replaced: the pure speed race let the writer outrun fwdma_free_multiseg (no reclaim window) or corrupt the slab freelist (wedged guest); the 4GB-RAM run of that design produced the mid-flight Fatal trap 12 supervisor write kept as panic.txt. Guest must be booted with -m 2048 for the kmalloc-backed (reclaimable) segment variant.",
  "attempts": 6,
  "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": 2700,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (cd /root/df5613 && make; compiles unmodified production firewire.c+fwdma.c+fwdev.c into df5613.ko)",
  "run_cmd": "sh run.sh  (kldload df5613.ko; sysctl kern.df5613_test=2 then =1; read kern.df5613_status) -- boot guest with QEMU_EXTRA=-m 2048",
  "code_hash": "5a26a18c783d915e6ecca2172729675f8d826d6638059c36beee0f933ed3b43d",
  "notes": "Known findings not re-reported: DF-1116/DF-2297 (esize==0 div-by-zero), DF-2298 (n int overflow -> 0-length seg array), DF-2299 (kmalloc NULL check), DF-5413 (crafted nchunk*npacket write-what-where -- this finding is the distinct claim/teardown lifetime hole that also reaches fwdma_free_multiseg), DF-5304 (HW-side disable window), DF-5414/5415/5416/5417 (other fwdev races), DF-1058 (len>psize overflow). The read-side mirror (fwdev.c:329 uiomove out of freed pages = arbitrary-read shape) shares the hole; write side demonstrated. fwdma buffer leak of the claim-race loser is code-certain (fwdev.c:103/108 pointer overwrite, no free) but not runtime-proven this run.",
  "recommended_fix": "Serialize and atomicize the iso-queue lifecycle: claim FWXFERQ_OPEN under crit_enter() BEFORE the sleeping fwdev_allocbuf() (clear on failure) in FW_STSTREAM/FW_SRSTREAM; clear q->stproc and re-init stvalid/stfree/stdma in fwdev_freebuf; re-check it->buf==NULL at the fw_read/fw_write loop tops (fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff applied to the guest /usr/src, harness module rebuilt from the patched production fwdev.c. Baseline: shared=YES, 62/62 OOB poffset entries (heap overflow CONFIRMED). Patched: FWXFERQ_OPEN visible set while fd1 is still inside fwdma_malloc_multiseg, fd2s STSTREAM claims a different queue (d2->it != fc.it[0]), shared=no overflow=0 -- the double-claim (and with it the two-fds-one-queue precondition of the teardown UAF) is gone. Residual ns-scale window between the new loop-top check and the uiomove is documented; full closure needs a refcount/lock across the I/O loops.",
  "fix_evidence": "fix_run.log (patched run trail), fix_build.log, fix.diff (dry-run verified against sys/bus/firewire/fwdev.c)"
}