# DF-2292 — FW_ASYREQ response copy overflows ioctl heap buffer (fwdev.c)

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

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

`FW_ASYREQ` is an ioctl on `/dev/fw<N>` (a per-FireWire-node device created when
a remote 1394 node is enumerated by an attached `fwohci` controller). The audit
guest has no FireWire controller and no `/dev/fw*` devices:

```
$ pciconf -l | grep -iE "fwohci|firewire"   # (no output)
$ ls /dev/fw*                                # /dev/fw*: No such file or directory
```

With no controller attached there is no FireWire bus, no enumerated nodes, no
`/dev/fw<N>`, and no peer that could answer an async-stream request with an
oversized RRESB response. The unprivileged `maxx` user cannot open a
non-existent device node. The `hw.firewire.*` sysctl defaults exist only because
the subsystem is compiled in.

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

The `struct fw_asyreq` ioctl argument (`firewire.h:251-266`) is:
```c
struct fw_asyreq {
    struct fw_asyreq_t { unsigned char sped; unsigned int type;
                         unsigned short len; union { struct fw_eui64 eui; } dst; } req;
    struct fw_pkt pkt;
    u_int32_t data[512];     /* fixed 2048-byte user buffer */
};
```

In `fw_ioctl`/`FW_ASYREQ` (`fwdev.c:538-587`), after sending the async request
and `tsleep`-ing for the response, the kernel copies the peer's response back
into the caller's `fw_asyreq`:

```c
/* copy response */
tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len)   /* fwdev.c:578 */
    asyreq->req.len = xfer->recv.pay_len;                     /* fwdev.c:579 */
else
    err = EINVAL;
bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);                   /* fwdev.c:582 */
bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len,
      MAX(0, asyreq->req.len - tinfo->hdr_len));              /* fwdev.c:583 */
```

The check at line 578 uses the **user-supplied `asyreq->req.len`** as a proxy
for the destination buffer's capacity. But the real capacity is the fixed
`data[512]` array (2048 bytes) beginning at `&asyreq->pkt`. Line 579 then sets
`asyreq->req.len = xfer->recv.pay_len` — the length of the **peer's** response
payload, which the kernel does not bound against the buffer. `recv.payload` is
allocated `PAGE_SIZE` (4096), so a malicious FireWire peer answering an RREQB
with an RRESB payload up to ~4080 bytes causes line 583's `bcopy` to write up to
~4080 bytes of attacker-controlled data into the 2048-byte `data[]` region — a
~2032-byte heap overflow of the `mapped_ioctl`-supplied buffer.

There is no `MAXREC` / `maxrec` clamp on the receive path. Impact (on hardware):
kernel heap corruption with controlled bytes from a FireWire peer; the operator
group can open `/dev/fw<N>` on DragonFly, so this is an unprivileged-user +
malicious-peer vector on firewire-equipped hosts.

## Exploit chain status

Not pursuable — primitive is behind absent FireWire hardware (valid Phase-6
hard blocker). On real hardware this is a write-capable heap-corruption
primitive.

## PoC changes

None. `/dev/fw*` absent; verified by source trace only.

## Recommended fix

Clamp the response copy to the actual destination capacity (the fixed `data[]`
array). See `fix.diff` (supersedes finding proposal: bounds-checks the bcopy
length against `sizeof(asyreq->data)` instead of trusting user `req.len`).
