# VERDICT — DF-2291 (verify mode)

**status: reproduced** · reproduced=1 · impact=leak · confidence=certain
rig: verbatim-code (guest has no FireWire hardware/KLD — see env.txt)

## Claim under test

`crom_parse_text()` (sys/bus/firewire/fwcrom.c:187-225) validates the text leaf with

```c
if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc))   /* fwcrom.c:207 */
```

but `crc_len` is a QUADLET count (see crom_add_simple_text, fwcrom.c:459:
`tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t))`), while the
read loop consumes `(crc_len - 2)` quadlets of `textleaf->text[]` (fwcrom.c:215-219),
i.e. a byte extent of `12 + (crc_len-2)*4 = 4*crc_len + 4`. The check is therefore ~4x
too permissive; a leaf near the buffer end passes validation and the loop reads past the
1024-byte ROM **with the default `info_len = 4`** — no dependency on DF-2290.

## How it was verified

Same verbatim rig as DF-2290 (production parser linked unmodified; sha256 in build.log).

1. **df2291_guard** — ROM: `info_len=4`, root dir @20 with one entry
   `{key=0x81 CROM_TEXTLEAF, val=244}` → leaf at byte 1000, `crc_len=10`. Buggy check:
   `1000 + 10 <= CROM_END(1023)` passes. Loop reads text[0..2] (bytes 1012..1023,
   in-bounds) then faults reading text[3] at **exactly buffer_end+0** (SIGSEGV,
   si_addr == rom+1024). Run 3/3 identical. → the read crosses the object boundary by
   up to 20 bytes (last byte at 1043).
2. **df2291_canary** — same ROM, canary page after the buffer. Output of
   `crom_parse_text` (the exact buffer that in production is `sdev->vendor` /
   `sdev->product`, sbp.c:606,621):
   `ab0de000 ab0de001 ab0de002 c0ffee00 c0ffee01 c0ffee02 c0ffee03 c0ffee04`
   — words 0..2 are the in-buffer markers, words 3..7 are canary read from bytes
   1024..1043, i.e. **adjacent-memory contents copied into the user-visible string**.
   The leak primitive is demonstrated end-to-end at parser level.
3. **control** — in-bounds leaf (byte 512, crc_len=6) parses correctly, guard page
   untouched → rig sanity.

Production context: hostile FireWire device's config ROM → `fw_device.csrrom[1024/4]`
(firewirereg.h:52-54, filled at firewire.c:1500 host-endian) → sbp target attach calls
`crom_parse_text(cc, sdev->vendor, sizeof(sdev->vendor))` and `..._product`
(sbp.c:602-621) → SCSI INQUIRY data readable by any local user with access to the sbp
LUN. Ceiling: the copy is clamped by the destination (`len`), and in the kernel path
`len = sizeof(sdev->vendor) = 32` (sbp.c:187,606) → up to 32 bytes of adjacent kernel
heap per text leaf reach the INQUIRY string (a leaf near CROM_END makes ALL 32 bytes
out-of-bounds-sourced; the read fault extent reaches ~43 bytes past the buffer).
`crom_parse_text` is called for both vendor and product (and the revision loop walks
more leaves), and a hostile ROM may contain many text leaves — each swept with the
broken bound. The userspace `fwcontrol`/`crom_desc` path passes larger `len`, reading
further. Read-only bug → leak class; Medium/kernleak as filed stands.

## Fix A/B (same rig, `fix.diff` hunk 2)

Baseline reproduces (above). With hunk 2 applied (bound the leaf's full byte extent:
`textleaf + (crc_len + 1) * sizeof(u_int32_t) > CROM_END`): both attack modes return
the safe `"(null)"` string, **no fault, no canary**; `control` still parses
(PARSED_INBOUNDS) — the stricter check accepts every legitimately-placed leaf because
`crom_load()` emits leaves whose quadlet extent is `crc_len` (fwcrom.c:459,521-523).
The `+1` term covers the loop's `4*crc_len + 4` reach exactly (one byte conservative
in the boundary case, which is unreachable for well-formed leaves).

## Honesty notes

- Same userspace-rig caveat as DF-2290: kernel adjacency + INQUIRY leg is source-cited,
  not executed (no FireWire hardware on the audit guest).
- The finding's arithmetic ("reads buffer+1012 through buffer+1043, up to 19 bytes
  past") is confirmed modulo the exact struct size: `struct csrtext` header is 12 bytes
  (BIT16x2 + spec + lang, iec13213.h:148-159), so text starts at leaf+12; for a leaf
  at 1000 the read extent is 1012..1043 → 20 bytes past the 1024-byte buffer end.
  Immaterial to the verdict.
- Interaction: DF-2290's fix is NOT required for this one (default info_len), but with
  both unfixed a hostile ROM can chain them (DF-2290 to widen CROM_END, DF-2291 to
  sweep larger windows past the buffer).

## Bottom line

Confirmed as filed: the `crc_len`-as-bytes check at fwcrom.c:207 lets a hostile text
leaf read past `fw_device.csrrom` (with DF-2290 chained, far past it), with the leaked
bytes landing in SCSI INQUIRY strings. One-line fix, A/B validated, no regression.

## 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.
