# DF-5414 — VERDICT

**reproduced · impact: UAF + double free (panic-class; overlap primitive proven) · confidence: certain**

Production fw_read() (fwdev.c:260-345) was driven twice against an ir->q
populated exactly the way the production FWACT_CH receive path populates it
(firewire.c:1883-1897: bind xfer, crit, queued++, STAILQ_INSERT_TAIL,
wakeup).  Result on the guest (fresh boot, fresh module load):

* read#1 returned 0 and **left the freed xfer linked**: `ir->q head ==
  0xfffff801176997c0 (STILL THE FREED XFER), queued=1` — the dequeue is
  `#if 0` (fwdev.c:305-317) while `fw_xfer_free()` (fwdev.c:318) is live.
* `fw_xfer_alloc()` immediately re-occupied the chunk (LIFO), proving the
  allocator considers it free while ir->q still points at it.
* read#2 called `fw_xfer_free()` on the same address again (UAF reads of
  xfer->state/xfer->fc/xfer->tl inside fw_xfer_unload, then kfree), and
  the two follow-up allocations **returned the same pointer twice**
  (`p1 == p2 == xfer`) — duplicate allocation = overlapping live kernel
  objects, the standard takeover primitive.

No allocator assumptions are needed for the core claim: the queue head
after read#1 *is* the freed pointer (deterministic, printed from the live
list), so read#2's free of it is unconditionally a double free.

Real-world trigger: one inbound FireWire async packet addressed to a
FW_SBINDADDR-bound range (any remote bus peer — FireWire is
unauthenticated), then read(2) twice on /dev/fwN.M.  The remote side is
hardware-gated in QEMU; the local corruption path ran as production code.

Fix validated (fix.diff: dequeue restored before free):
`read#1 err=0 -- ir->q head=0 queued=0` (dequeued!), read#2 errs out,
`p2 != p1`, no duplicate allocation, guest alive (fix_run.log).

Harness quirks documented in DF-5413/VERDICT.md (module entry via the
included firewire.c DRIVER_MODULE; guard shims; fake devclass).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
