# DF-2290 — unchecked `info_len` in `crom_init_context` → OOB heap reads past `csrrom[]`

**Status: REPRODUCED (verbatim-code rig)** — impact class: kernel info leak (OOB read).
**Fix: A/B-validated in the same rig** (`fix.diff` hunk 1).

## What this pack contains

| file | role |
|---|---|
| `fwcrom_rig.c` | verbatim-code rig: drives the UNMODIFIED production parser |
| `build.sh` | builds `fwcrom_rig` (baseline, links `/usr/src/sys/bus/firewire/fwcrom.c` verbatim) and `fwcrom_rig_fixed` (`fix.diff` applied to a local copy; `sys/` never touched) |
| `run.sh` | evidence run: `df2290_guard`, `df2290_canary`, `control` × {baseline, patched} |
| `run.log`, `run.2.log`, `run.3.log` | three full untrimmed runs (deterministic, identical results) |
| `build.log` | full compiler + patch output from the guest |
| `fix.diff` | git-apply-able unified diff (both DF-2290 and DF-2291 hunks) |
| `env.txt` | guest uname, cc, sha256 of the guest's kernel source file, no-firewire evidence |
| `VERDICT.md`, `manifest.json`, `verdict.json` | verdict narrative + machine-readable results |

## How to reproduce

On a DragonFlyBSD guest with `/usr/src` present:

```sh
./build.sh          # links the production parser verbatim (sha256 printed & verified)
./run.sh            # 6 cells: 3 modes x {baseline, fix.diff-patched}
```

## Expected output (baseline = unmodified production code)

```
RIG mode=df2290_guard result=OOB_FAULT_CONFIRMED
  ... fault address is 3 bytes past the buffer end        # SIGSEGV on root entry[0], quadlet [1024,1028)
RIG mode=df2290_canary result=OOB_LEAK_CONFIRMED
  crom_search_key(0x03) returned reg=... (buffer+1052; 28 bytes PAST the 1024-byte buffer)
  reg->key=0x03 reg->val=0xc0ffee  <- value read from memory OUTSIDE the buffer
RIG mode=control result=PARSED_INBOUNDS                   # rig sanity, guard page untouched
```

With `fwcrom_rig_fixed` (fix.diff applied): `REJECTED_NO_FAULT` for both attack modes
(`crom_init_context: info_len 254 out of range`), `control` still `PARSED_INBOUNDS`.

## Attacker input (the crafted ROM)

`rom[0] = info_len<<24` with `info_len = 254`; `rom[255]` = root directory header
(`crc_len = 0x100`). That is byte-identical to what a hostile FireWire device sends in
its config ROM bus-info block — the kernel stores it host-endian into
`fw_device.csrrom[1024/4]` (`firewire.c:1500`).
