# DF-1085 — `crom_parse_text()` write-underflow when text leaf `crc_len < 2`

**File:** `sys/bus/firewire/fwcrom.c:215`  · **Severity:** High
**Class:** CWE-787 Out-of-bounds Write

## TL;DR

`crom_parse_text` subtracts 2 from a 16-bit `textleaf->crc_len` without
checking it is `>= 2`.  If a (malicious) FireWire device's Configuration
ROM has a text leaf with `crc_len` of 0 or 1, the signed `qlen` underflows
to −2/−1 and the NUL-terminator write at `fwcrom.c:224`
(`buf[qlen*4] = 0`) lands **4 or 8 bytes before `buf`** — a single-byte
OOB write.  In the SBP-2 caller (`sbp.c:606/621`) `buf` is
`sdev->vendor` / `sdev->product` and `buf[-8]` aliases the high byte of
`sdev->free_ocbs.tqh_last`, a kernel heap pointer later dereferenced by
the SBP-2 driver's free-OCB queue ops.

This guest has **no FireWire controller**, so the live in-kernel path is
not exercisable; the primitive is proven at the harness level using the
**verbatim kernel code** (same situation as DF-1083 / DF-0594 / DF-0616 /
DF-0281).

## Reproduce

On the DragonFly guest as any user:

```
./build.sh && ./run.sh
```

- `harness`        — verbatim `crom_parse_text` logic; expects
                     `>>> OVERALL: BUG CONFIRMED` (exit 1).
- `harness_fixed`  — same code + the `crc_len < 2` guard from `fix.diff`;
                     expects `>>> OVERALL: canary intact` (exit 0).

Build: `cc -O0 -g -Wall` (cc 8.3, DragonFly).  No special libraries.

## Expected output (bug present)

```
[crc_len=0] >>> BUG CONFIRMED: pre[8] (== buf[-8]) was zeroed by buf[qlen*4]=0 with qlen=-2
[crc_len=1] >>> BUG CONFIRMED: pre[12] (== buf[-4]) was zeroed by buf[qlen*4]=0 with qlen=-1
[crc_len=2 (legal minimum)] canary intact: no underflow write (crc_len guard fired).
>>> OVERALL: BUG CONFIRMED — crom_parse_text writes out of bounds when crc_len < 2.
```

## Fix

`fix.diff` — at `fwcrom.c:215`, reject malformed leaves with
`crc_len < 2` before the subtraction:

```diff
+	if (textleaf->crc_len < 2) {
+		strncpy(buf, nullstr, len);
+		return;
+	}
 	qlen = textleaf->crc_len - 2;
```

Validated on a single-fix kernel (`6.5-DEVELOPMENT #1`,
`sha256 cc74c4ec…`); disassembly of the running `crom_parse_text`
shows the `cmp $0x1,%ax; jbe strncpy_path` guard before `sub $0x2,%eax`.
See `VERDICT.md` and `crom_parse_text_patched.disasm` for details.

## Files in this folder

| File                            | Purpose                                                  |
|---------------------------------|----------------------------------------------------------|
| `harness.c`                     | verbatim-kernel-code userspace repro (BUGGY logic)       |
| `harness_fixed.c`               | same code + crc_len<2 guard (FIXED logic)                |
| `build.sh` / `run.sh`           | exact build & run commands                               |
| `fix.diff`                      | `git apply`-able one-hunk fix for `fwcrom.c`             |
| `run.log` / `run.2.log`         | full BUG-CONFIRMED output (baseline, 2 runs)             |
| `run_fixed.log`                 | full canary-intact output (fixed logic)                  |
| `baseline_run.log`              | re-confirmed on `#0` unpatched kernel after `vm.sh reset`|
| `fix_build.log`                 | full `make nativekernel` log (rc=0)                      |
| `crom_parse_text_patched.disasm`| objdump of patched `crom_parse_text` + kern.version      |
| `panic.txt`                     | underflow math + harness observation summary             |
| `env.txt`                       | guest uname, cc, CPU features, kernel config             |
| `VERDICT.md`                    | full narrative: mechanism, reachability, fix validation  |
| `manifest.json`                 | machine-readable catalog                                 |
