# DF-1360 — VERDICT

**Verdict: INCONCLUSIVE (real bug, needs hardware absent from guest).** Source
trace confirms the vulnerability; it cannot be executed on this QEMU guest
because `/dev/mps0` does not exist (no LSI MPS SAS HBA), so the PoC fails at
`open()` with `ENOENT`. Fix validated to apply + compile in a clean `mps.ko`
module build.

This is the **mps driver's twin of DF-1328** (the identical bug in the `mpr`
driver's `mpr_user.c`).

## Mechanism

```
sys/dev/raid/mps/mps_user.c:1856   size = data->Size;                       // uint32_t, user-controlled
sys/dev/raid/mps/mps_user.c:1857   if ((size >= sizeof(sc->recorded_events)) && (status == 0)) {
sys/dev/raid/mps/mps_user.c:1858       mps_unlock(sc);
sys/dev/raid/mps/mps_user.c:1859       if (copyout((void *)sc->recorded_events,
sys/dev/raid/mps/mps_user.c:1860           PTRIN(data->PtrEvents), size) != 0)    // *** LEAK: len = user size ***
sys/dev/raid/mps/mps_user.c:1861           status = EFAULT;
```

`sizeof(sc->recorded_events)` = `MPS_EVENT_QUEUE_SIZE` (50, `mps_ioctl.h:207`)
× `sizeof(mps_event_entry_t)` (= `4+4+4*MPS_MAX_EVENT_DATA_LENGTH(48)` = 200,
`mps_ioctl.h:224-230`) = **10000 bytes** (`mpsvar.h:414`).

The gate at 1857 is a **lower** bound (`size >= 10000`), not an upper bound.
The `copyout` length is the **user-supplied `size`**, which can be up to
`0xFFFFFFFF`. Setting `size = 256 KiB` reads 256 KiB out of `recorded_events`:
10000 bytes of the array plus ~240 KiB of whatever follows it inside
`struct mps_softc` (DMA bus addresses, kernel pointers, locks, command rings)
and into adjacent kernel heap. Deterministic kernel-heap information leak.

## Reachability on this guest

`mps` is a `device` in `X86_64_GENERIC` but no SAS HBA is present → driver never
attaches → no `/dev/mps0` → PoC fails at `open()`:
```
poc: open /dev/mps0: No such file or directory  (errno=2)
poc: mps driver not attached on this guest (no SAS HBA) -> cannot reach mps_user_event_report.
RUN_EXIT=1
```
Privilege model (same as mpr, `make_dev UID_ROOT/GID_OPERATOR 0640`,
`mps_open` returns 0, no `priv_check` in `mps_ioctl`): reachable by root or
operator-group users on an mps-equipped host. Phase-4(d): real code path,
unreachable on this guest due to absent hardware.

## Exploit chain

None — read-only OOB info leak, no corruption primitive. Impact ceiling:
deterministic disclosure of the `mps_softc` tail (DMA addresses, kernel
pointers) and adjacent heap, repeated to taste → KASLR bypass / heap-layout
reconnaissance.

## PoC changes

Folder was empty. Authored `poc.c` (opens `/dev/mps0`, issues
`MPTIOCTL_EVENT_REPORT` with `Size = 256 KiB`, would dump bytes 10000..10064 of
the softc tail), `build.sh`, `run.sh`.

## Fix

`fix.diff` makes the copyout length `sizeof(sc->recorded_events)` (the fixed
array size) instead of the user-controlled `size`. The `size >=` gate remains
the "did the user give a big enough buffer?" check; the actual bytes copied are
now exactly the array. Applies cleanly (`patch --dry-run` hunk @1857) and the
clean `mps.ko` build succeeds (`rc=0` — `fix_build.log`). Matches the finding's
proposed fix (`clamp size to sizeof(recorded_events)`).

## Fix validation

`fix_status: not_testable` — PoC cannot run (no `/dev/mps0`). Fix validated by
apply + clean module compile + code-path inspection (copyout length is now the
constant array size, independent of `data->Size`).
