# DF-5156 — orm(4) identify loop missing MAX_ROMS bound — PoC evidence pack

## What this tests

`orm_identify()` (sys/dev/misc/orm/orm.c:104-150) fills `sc->rid[]`/`sc->res[]`
(`MAX_ROMS`=16 entries, orm.c:56-62) once per *valid* option-ROM signature
(`55 AA`, size byte multiple of 4) found while scanning the ISA hole
(0xa0000-0xfffff, 2KB steps). The loop condition is only `chunk < IOMEM_END`
(orm.c:104) — there is **no `sc->rnum < MAX_ROMS` check** before the writes at
orm.c:146-147. If more than 16 signatures exist, the kernel writes kernel
pointers/ints past the 196-byte `orm_softc` (heap overflow at boot), and
`&sc->rid[16]` aliases `&sc->res[0]`, corrupting the already-stored resource
pointers.

Threat model: attacker-controlled firmware / option-ROM content delivered into
the ISA hole (flashed PCI/ISA option ROM, VM firmware image).

## How to reproduce (what was done here)

1. `python3 gen_orm_rom.py` — builds `orm-evil.rom` (97,280 bytes):
   outer header `55 AA BE` (0xBE&3==2 → the orm scan itself *skips* the base
   but SeaBIOS copies the full file), an immediate `RETF` (0xCB) at offset 3
   of **every** 2KB block (SeaBIOS enters ISA ROMs at seg:0003 — without this
   the zero body gets executed and hangs the BIOS), and `55 AA 04` (2KB "ROM")
   at each internal 2KB boundary → 47 fake ROM signatures.
2. Boot the audit guest with the ROM injected (QEMU 7.2, SeaBIOS):

       cd dfbsd-qemu
       QEMU_EXTRA="-option-rom /home/maxx/dfbsd/dfbsd/findings/poc/DF-5156/orm-evil.rom" ./vm.sh up

3. Observe `dmesg | grep orm` / `devinfo -r` / memory dump.

## Expected (per the unbounded code) vs actual

* Expected if the bound were reachable: rnum reaches 47(+1) → 31 pairs of OOB
  writes past the softc (`sc->rid[16..47]`, `sc->res[16..47]`), likely panic
  during autoconf; `&rid[16+i]` corrupting `res[i]` low halves.
* **Actual (2 runs): `orm0: <ISA Option ROMs> at iomem 0xcb800-...-0xcf7ff` —
  exactly 8 regions, guest boots and runs normally, no panic.** Headers are
  verifiably present in RAM at 0xcb800, 0xcf800 and 0xe2800 (run.log) — the
  scan saw them and silently stopped recording at 8.

## Why it does not manifest (root cause of the containment)

The ISA bus layer caps memory rids below orm's array size:

* `isa_set_resource()` (sys/bus/isa/isa_common.c:897-899) returns EINVAL for
  `SYS_RES_MEMORY` with `rid >= ISA_NMEM` (8) — and orm.c:105-106 ignores the
  return value of `bus_set_resource()`.
* With no resource-list entry, `bus_alloc_resource_any()` →
  `resource_list_alloc()` (sys/kern/subr_bus.c:2693-2695) returns NULL →
  orm.c:141-144 silently skips the region (`chunk += IOMEM_STEP`).
* Hence `sc->rnum ≤ 8 < MAX_ROMS=16` on every boot. The only ISA
  implementation in the tree is `sys/bus/isa/x86_64/isa.c` (platforms: pc64,
  vkernel64; no i386), so this holds on **all supported DragonFly platforms**.

## Files

* `gen_orm_rom.py` — option-ROM generator (the PoC source)
* `orm-evil.rom` — generated image (sha256 ff6aa6fe…324bd)
* `run.log`, `run.2.log` — decisive guest outputs (2 independent boots)
* `seabios-attempts.txt` — SeaBIOS debug-port captures of the failed attempts
* `env.txt` — guest/QEMU identity
* `fix.diff` — defense-in-depth bound check (not applied; bug latent)
* `verdict.json`, `manifest.json`
