# DF-1060 — FW_GTPMAP bcopy with attacker-inflatable crc_len (OOB read)

## Verdict
**NOT REPRODUCED** — code-confirmed latent bug; cannot trigger on this guest (no FireWire PCI controller, `/dev/fw*` absent). Also: the OOB read requires `crc_len` to have already been inflated by a malicious FireWire device, which is itself an out-of-guest precondition.

## Mechanism (source-confirmed)

In `sys/bus/firewire/fwdev.c:fw_ioctl`:

```c
case FW_GTPMAP:
    bcopy(sc->fc->topology_map, ap->a_data,
            (sc->fc->topology_map->crc_len + 1) * 4);
    break;
```

- `topology_map` is allocated as exactly `sizeof(struct fw_topology_map)` ≈ 1036 bytes (`sys/bus/firewire/firewire.c:738`).
- `crc_len` is `uint16_t`, so the count can be up to `(65535+1)*4 = 262144` bytes.
- `crc_len` is incremented once per received self-id packet in `fw_sidrcv` at `firewire.c:1143` without any bound against the `topology_map` allocation. The related `sid_cnt = len/8` at `firewire.c:1124` is also unvalidated.
- Once `crc_len > ~258`, the `bcopy` reads past the `topology_map` allocation and writes those kernel heap bytes into the user buffer. With a very large `crc_len` the `bcopy` may walk into an unmapped kernel page → panic.

The user-side `FW_GTPMAP` call therefore (a) leaks kernel heap bytes when `crc_len` has been inflated, and (b) can panic the kernel.

## Why not reproduced on this guest

Two stacked absent preconditions:
1. The QEMU audit guest has no FireWire PCI host controller, so no `firewire0` instance, no `/dev/fw*` device node, and no way to issue `FW_GTPMAP`. (`kldstat -v` shows the `fwohci/firewire` driver present in the kernel, but inert.)
2. Even on a FW-equipped host, the leak requires `crc_len` to already be inflated — either by a malicious/buggy FireWire device flooding self-id packets, or by trigger of the related `self_id[256]` OOB write at `firewire.c:1142`. Without that, a benign system has `crc_len ≤ ~258` and the `bcopy` stays in-bounds.

Per Phase-4(c)/(d): real bug, doubly-unreachable on this guest. Source-only confirmation; the bug is latent.

## Fix

`fix.diff` caps `crc_len` at `sizeof(struct fw_topology_map)/4 - 1` (the maximum that fits in the allocation):

```c
case FW_GTPMAP:
    {
        u_int cl = sc->fc->topology_map->crc_len;
        u_int maxcl = sizeof(struct fw_topology_map) / 4 - 1;
        if (cl > maxcl)
            cl = maxcl;
        bcopy(sc->fc->topology_map, ap->a_data, (cl + 1) * 4);
    }
    break;
```

A complete fix would ALSO bound the self-id loop in `fw_sidrcv` (`firewire.c:1136-1183`) at `4*64` entries and stop incrementing `crc_len` past that — that is a separate code change recommended in the finding markdown but out of scope for the user-side `FW_GTPMAP` OOB read. Validated as part of a combined 5-patch kernel build that compiled cleanly and booted.

## Kernel references
- `sys/bus/firewire/fwdev.c:657-660` — `FW_GTPMAP` bcopy with unbounded count
- `sys/bus/firewire/firewire.c:738` — `topology_map` allocation size
- `sys/bus/firewire/firewire.c:1124, 1142-1143` — `crc_len` increment in `fw_sidrcv` (unbounded)
- `sys/bus/firewire/firewire.h` — `struct fw_topology_map` (room for 256 self_ids)

## PoC changes
`fw_gtpmap_oob_read.c` is doc-only. `fix.diff` is git-apply-able and verified to apply + compile as part of a combined patched-kernel build.
