# DF-2288 — OOB heap write/read in fw_bus_explore_callback (CSR ROM parser)

## Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)

## Hardware gate (why the PoC cannot run on this guest)

The DragonFlyBSD audit guest is a QEMU/KVM VM with **no FireWire (IEEE 1394)
hardware whatsoever**. Confirmed at audit time:

```
$ pciconf -l          # no fwohci / firewire bridge present
hostb0@pci0:0:0:0:   class=0x060000 ...  (i440fx hostbridge)
isab1@pci0:0:1:0:    class=0x060100 ...  (PIIX3 ISA bridge)
atapci0@pci0:0:1:1:  class=0x010180 ...  (PIIX3 IDE)
vgapci0@pci0:0:2:0:  class=0x030000 ...  (Bochs/QEMU std VGA)
virtio_pci0/1 ...                           (net + blk)
$ ls /dev/fw*         # /dev/fw*: No such file or directory
$ ifconfig -l         # vtnet0 lo0  (no fwip/fwe firewire net iface)
```

There is no FireWire controller (`fwohci`) attached, no `/dev/fw*` character
device, and no firewire network interface. The vulnerable path
`fw_bus_explore_callback()` runs **only** in the FireWire stack's bus-enumeration
state machine, which is driven by `fwohci` interrupt delivery from real 1394
hardware during bus exploration. With no `fwohci` device and no `/dev/fw*` node
reachable by the unprivileged `maxx` user, the callback can never be driven by
attacker-controlled Config-ROM responses on this guest.

The `hw.firewire.*` sysctl nodes exist only because the firewire subsystem is
compiled into the kernel; they are inert defaults — `pciconf -l` proves no
controller is probed/attached.

## Source trace — the bug is REAL (sys/bus/firewire/firewire.c)

The claim is accurate. The write happens BEFORE the bounds check, the bounds
check is an off-by-one (`>` instead of `>=`), and the directory-entry jump
advances `ongoaddr` with no bounds check at all.

`fw_device` carries `u_int32_t csrrom[CSRROMSIZE/4]` = `csrrom[0x400/4]` =
`csrrom[256]` (sys/bus/firewire/firewirereg.h:51-54; `CSRROMOFF = CSRROMSIZE =
0x400`). Valid offsets are `csrrom[0..255]`.

1. **Write-before-check.** `firewire.c:1500`:
   ```c
   fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4] = ntohl(rfp->mode.rresq.data);
   ```
   stores the attacker-controlled (peer-supplied) 4-byte Config-ROM quadlet into
   `csrrom[]` indexed by `ongoaddr` **unconditionally**, then the only bounds
   check appears ~58 lines later at `firewire.c:1558`:
   ```c
   if((fc->ongoaddr - CSRROMOFF) > CSRROMSIZE){   // > should be >=
       goto nextnode;
   }
   ```
   So `ongoaddr == CSRROMOFF + CSRROMSIZE` (index 256, one past end) is written
   first and only then (incorrectly) allowed through.

2. **Unbounded directory-entry jump.** `firewire.c:1514-1524`:
   when the parser sees a Unit-/Directory-entry key (`0x81`/`0xd1`) it does
   ```c
   fc->ongoaddr += csrreg->val * 4;     // firewire.c:1520
   ```
   `csrreg->val` is a 24-bit field taken directly from the (malicious) ROM with
   **no upper bound**. A crafted ROM can therefore advance `ongoaddr` far past
   `CSRROMSIZE`, and the next callback iteration writes attacker bytes at
   `csrrom[(ongoaddr-CSRROMOFF)/4]` deep past the end of the `fw_device` heap
   object. On amd64 `csrrom[0x101]/[0x102]` alias the low/high halves of the
   following `fc` pointer (`firewirereg.h` fw_device layout), yielding a
   controlled kernel-pointer dereference in `fwmem_xfer_req`.

3. **Info-leak path.** `rommax` is set to `ongoaddr` with no upper bound
   (`firewire.c:1501-1503`), and the General-Config-ROM copyout (`FW_GCROM`)
   later copies `csrrom[]` out to userspace, leaking post-buffer kernel heap.

Impact (on real FireWire hardware, absent here): kernel heap write of
attacker-controlled value at an attacker-influenced offset, plus a kernel-heap
info-leak via FW_GCROM. Trigger: any device physically on the IEEE 1394 bus; no
authentication.

## Exploit chain status

Not pursuable on this guest — the primitive is gated behind absent FireWire
hardware (valid Phase-6 hard blocker: "vulnerable code path dead/unreachable at
runtime on this guest AND no harness can exercise it" because it requires a live
1394 peer responding with crafted ROM quadlets). The bug is a real, write-capable
heap-corruption primitive on hardware that owns a 1394 controller; the
defense-in-depth fix below closes it.

## PoC changes

None. No PoC source was authored or runnable: the `/dev/fw*` device does not
exist and the `fwohci` controller is absent, so neither a userspace ioctl
reproducer (which would need an attached FireWire peer's responses) nor a kernel
harness can drive `fw_bus_explore_callback` on this guest. The README claim was
verified purely by source trace.

## Recommended fix

Bound `ongoaddr` *before* the write and fix the off-by-one. See `fix.diff`
(supersedes finding proposal by hardening the directory-jump path the finding
markdown focuses on, plus the `>`→`>=` correction).
