# DF-2289 — Off-by-one stack overflow in crom_next depth guard (fwcrom.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)

`crom_next()` parses IEEE 1394 Configuration ROM and is reached via the FireWire
stack (e.g. `crom_init_context` / `crom_search_key` invoked while enumerating
remote nodes). The audit QEMU/KVM guest has **no FireWire controller** and no
`/dev/fw*` device:

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

Without an `fwohci` controller and a live 1394 peer there is no path to feed a
crafted Config-ROM into `crom_next`. The unprivileged `maxx` user cannot open
`/dev/fw*` (it does not exist), so no ioctl or userspace path reaches the parser
on this guest.

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

Layout (`iec13213.h:200-209`):
```c
#define CROM_MAX_DEPTH  10
struct crom_ptr   { struct csrdirectory *dir; int index; };
struct crom_context { int depth; struct crom_ptr stack[CROM_MAX_DEPTH]; };
                                       /* stack[0..9], 10 elements */
```

`crom_next()` (`fwcrom.c:106-143`):
```c
reg = crom_get(cc);                          /* cc->stack[cc->depth] */
if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
    if (cc->depth >= CROM_MAX_DEPTH) {       /* line 115: checks BEFORE incr */
        kprintf("crom_next: too deep\n");
        goto again;
    }
    cc->depth ++;                            /* line 119: now depth == 10 */
    ptr = &cc->stack[cc->depth];             /* line 121: &stack[10] = ONE PAST END */
    ptr->dir  = (struct csrdirectory *)(reg + reg->val);  /* 8-byte attacker ptr */
    ptr->index = 0;                          /* + 4 bytes */
    goto check;
}
```

The guard at line 115 fires only when `depth >= 10`, but the array's last legal
index is `9`. So when the parser enters `crom_next` at `depth == 9` (10th level
of nesting already reached) and the current entry is a directory
(`CSRTYPE_D`), the guard `9 >= 10` is false, execution proceeds to `cc->depth++`
(now 10) and `ptr = &cc->stack[10]` — one past the end of the 10-element array.
`ptr->dir` (an 8-byte attacker-controlled pointer derived from `reg->val`) and
`ptr->index` (4 bytes) are then written, a **16-byte stack overflow** into
whatever follows `crom_context.stack[]` (saved registers / adjacent locals). The
correct guard is `cc->depth >= CROM_MAX_DEPTH - 1` (i.e. `>= 9`), or move the
increment-before-check.

After the overflow, `goto check` dereferences `ptr->dir->crc_len`
(`fwcrom.c:130`) — an attacker-controlled pointer read → kernel info-leak or
panic.

Trigger: a malicious FireWire device whose Config ROM contains a chain of 10
nested `CSRTYPE_D` directory entries. No authentication; physical bus access.

## Exploit chain status

Not pursuable — primitive is behind absent FireWire hardware (valid Phase-6
hard blocker: dead path at runtime + no harness can drive it on this guest
without a live 1394 peer). The bug is a real 16-byte controlled stack overflow
on FireWire-equipped hardware.

## PoC changes

None. No PoC runnable: `/dev/fw*` absent, `fwohci` controller absent. Verified
by source trace only.

## Recommended fix

Tighten the depth guard so the increment never reaches the sentinel index. See
`fix.diff` (matches the finding proposal's intent — guard against
`depth >= CROM_MAX_DEPTH - 1`).
