# DF-1283 — VERDICT

**Verdict: REPRODUCED (primitive confirmed at object/harness level; runtime path is hardware-bound and not present on the audit guest).**

## Mechanism (source trace)

`_mapping_add_new_device` (`sys/dev/raid/mpr/mpr_mapping.c:1573`) processes a
SAS topology-change list and inserts each newly-added device into the mapping
table.

1. **Index arithmetic** — `mpr_mapping.c:1637-1638`:
   ```c
   map_idx = et_entry->start_index + phy_change->slot - et_entry->start_slot;
   ```
   Types: `map_idx` `u32` (`:1579`); `phy_change->slot` `uint16_t`
   (`mpr_mapping.h:48`); `et_entry->start_slot` `u16` (`mprvar.h:148`);
   `et_entry->start_index` `u32` (`mprvar.h:143`). `slot` comes from the SAS
   Device Page 0; `start_slot` from the Enclosure Status Change event — both
   firmware-controlled.

2. **Unguarded sink** — `mpr_mapping.c:1639`:
   ```c
   mt_entry = &sc->mapping_table[map_idx];   /* no bounds check */
   ```
   `mapping_table` has `max_devices` entries (`:2140`).

3. **Identical twin** at `:1894-1896` in `_mapping_add_new_pcie_device`.

There is **no** `slot >= start_slot` guard and **no** `map_idx < max_devices`
guard. Two OOB write modes:

- **slot too large** (Case A in the harness): `start_index + slot - start_slot`
  exceeds `max_devices` → write past the allocation into the adjacent slab
  object.
- **underflow** (Case B): `slot < start_slot` → the unsigned result wraps to a
  value near `0xFFFFFFFF` → wild out-of-slab pointer write (in-kernel: panic /
  wild write; in userspace: SIGSEGV).

## Primitive characterization

- **Write size:** one `struct dev_mapping_table` entry (32 bytes), attacker-shaped
  (`physical_id`, `dev_handle`, `device_info`).
- **Target:** `mapping_table` slab adjacency, or — in the underflow case — a
  near-arbitrary kernel address (controlled only by `start_index/slot/start_slot`
  magnitude).

## Harness proof

`harness.c` replays the exact arithmetic. Output (`run.log`):
```
Case A: start_index=10 slot=300 start_slot=0 -> map_idx=310 (0x136)
  BUG: map_idx=310 >= max_devices=264 -> write at mapping_table[310]   (adjacent-slab corruption)
Case B: start_index=0 slot=0 start_slot=5 -> map_idx=4294967291 (0xfffffffb)
  BUG: ... -- WILD POINTER (in-kernel: out-of-slab write / panic)
RESULT: OOB write into adjacent slab region DEMONSTRATED
```
The underflow case produces `0xFFFFFFFB` — exactly the wild pointer the kernel
would dereference.

## Why not a live in-kernel reproduction (valid hard blocker)

Same as DF-1282: `mpr` is hardware-bound (no SAS HBA in the QEMU guest), so the
topology-change path that calls `_mapping_add_new_device` never runs here. Live
trigger conditions: an `mpr`-attached HBA plus a topology event carrying a
malicious slot or enclosure start_slot (malicious peripheral / expander /
firmware / NVRAM corruption / passed-through HBA to a malicious VM). Primitive
proven at the object/harness level. Escalation to `uid=0` requires the primitive
to fire in a running kernel (groom the slab so the wild/adjacent write hits a
function-pointer / `ucred`-bearing victim) — not demonstrable on this guest
because the driver never attaches. Honest reported impact: the corruption
primitive itself.

## Fix

`fix.diff` adds `slot < start_slot || map_idx >= sc->max_devices` guards to both
the SAS (`:1637`) and PCIe (`:1894`) paths, `continue`-ing on violation.
**Validated:** `patch -p1` succeeds (both hunks), and the full `mpr` module
builds with `-Werror` (`mpr.ko` produced). Supersedes any pre-verification
proposal by covering both the SAS and PCIe twins.

## Fix-validation status

`not_testable` for a *live* before/after (PoC driver path cannot run on the
guest). Evidence the fix is correct: (1) harness before/after shows the guard
closes both the OOB and the underflow; (2) the fix compiles cleanly in-tree
under `-Werror`.
