# DF-4330 — mrsas `mr_update_span_set` OOB kernel write via firmware `spanDepth`

File: `sys/dev/raid/mrsas/mrsas_fp.c:949-959` (write at :955), reached from
`MR_ValidateMapInfo` (`:247-274`) at adapter attach (`mrsas.c:1762`) and on
every AEN RAID-map sync (`mrsas.c:2961`).

## What the PoC does

`fp_probe.ko` embeds the **unmodified** guest kernel source
`/usr/src/sys/dev/raid/mrsas/mrsas_fp.c` (globals renamed via `rename.h` so the
KLD does not collide with the built-in driver) and calls the real
`MR_ValidateMapInfo()` — the exact entry the driver calls at attach and on map
sync — on a firmware-shaped `MR_FW_RAID_MAP_ALL` with:

* `ldTgtIdToLd[63] = 63` (expose LD 63),
* `ldSpanMap[63].ldRaid.spanDepth = 64` (**> `MAX_RAIDMAP_SPAN_DEPTH` = 8**),
* `totalSize` forged consistent with `ldCount = 1` (passes the driver's only
  check), and
* a real `struct mrsas_softc` whose tail (`log_to_span[]` is the **last
  member**, `mrsas.h:2424`) is followed by a 4096-byte `0xAA` guard.

`mr_update_span_set`'s inner loop `for (count = 0; count < raid->spanDepth;
count++) span_set->strip_offset[count] = span_row_width;` writes
`strip_offset[MAX_SPAN_DEPTH = 8]` far out of bounds — across the following
`LD_SPAN_SET`s, across `ldSpanInfo[ld+1..]`, and for LD 63 past the end of
`sc->log_to_span[64]`, i.e. **past the end of the mrsas_softc allocation**
into adjacent kernel heap. The written bytes are the running sum of
firmware-chosen `spanRowDataSize` values.

## Build (guest, root)

```
sh build.sh            # builds /root/fp4330/fp_probe.ko (unmodified mrsas_fp.c)
                       # and    /root/fp4330_fixed/fp_probe.ko (fix.diff applied)
```

## Run (guest, root)

```
kldload /root/fp4330/fp_probe.ko
sysctl hw.fp_probe_run=0        # sanity: benign map -> accepted, guard intact
sysctl hw.fp_probe_run=1        # DF-4330: spanDepth=64 -> OOB write
kldunload fp_probe
```

## Expected output (see run.log)

```
fp_probe: MR_ValidateMapInfo returned 0 (0 == map accepted, spansets built)
fp_probe: *** DF-4330 CONFIRMED: OOB WRITE past end of sc->log_to_span[64] ...
fp_probe: guard integrity: 40/4096 bytes clobbered past softc end
```

40 bytes past the softc tail, values exactly the accumulated widths
(0x00..0x27 at +0..+39 with per-span `spanRowDataSize = 1`) — deterministic,
firmware-controlled content.

## Fix validation (see fix_run.log, fix.diff)

```
kldload /root/fp4330_fixed/fp_probe.ko     # mrsas_fp.c patched with fix.diff
sysctl hw.fp_probe_run=0        # benign map still ACCEPTED (no regression)
sysctl hw.fp_probe_run=1        # bad map REJECTED: "invalid RAID map geometry",
                                # returned 1, guard 0/4096 - OOB write GONE
```

The fix adds per-LD geometry validation (spanDepth, noElements, quad diff,
spanRowSize) to `MR_ValidateMapInfo` before any spanset is built.

## Threat model

The RAID map is DMA'd verbatim from the adapter (`mrsas.c:3135-3174`,
`MR_DCMD_LD_MAP_GET_INFO`) and nothing bounds `spanDepth` before the write
loop. Trigger requires a malicious/buggy MegaRAID SAS firmware or PCIe device
(same precondition as the known read-side finding DF-1528, but this is a
**write** primitive into kernel heap with attacker(fw)-chosen bytes).
