# DF-1696 — mps mpssas_evt_handler u16 truncation -> undersized/zero alloc -> near-NULL deref

## Verdict

**REPRODUCED (code-confirmed via harness).** Source-trace confirms the bug
at `sys/dev/raid/mps/mps_sas_lsi.c:128-145`. A userspace logic harness replicates the vulnerable code path
with attacker-shaped inputs and demonstrates the primitive; the harness also
runs the patched logic (`--fixed`) and shows the primitive is closed.

Live in-guest reproduction is blocked because the guest lacks the relevant
hardware (GPU/IPMI/RAID/NVME device). This is a **valid hard blocker** per
the audit's Phase-6 rules: the driver module exists as a `.ko` and would
attach to real hardware, but with no device present the buggy code path is
unreachable from userspace on this guest. On a system with the hardware
present, the bug fires at the cited line.

## Mechanism

mpssas_evt_handler declares 'u16 sz;' then computes sz = le16toh(event->EventDataLength) * 4. C promotes the product to int (max 262140) but the u16 assignment truncates. For EventDataLength >= 0x4000, sz wraps to 0 -> kmalloc(0) returns ZERO_LENGTH_PTR (-8 per kern_slaballoc.c:888 short-circuit); the non-NULL check at 142 passes; bcopy(event->EventData, fw_event->event_data=-8, 0) does nothing; first deref in mpssas_fw_work reads near-NULL -> fatal page fault. For 0x4001..0x7FFF, sz wraps to 4..65532 -> undersized alloc, then the struct-field accesses in mpssas_fw_work read/write past the allocation -> heap OOB. The event comes from the LSI SAS HBA (MPI2_EVENT_NOTIFICATION_REPLY) — device-controlled.

## Harness output

```
EventDataLength=0x4000 -> buggy sz=0 (truncated)
EventDataLength=0x4001 -> buggy sz=4 (truncated)
EventDataLength=0x6000 -> buggy sz=32768 (truncated)
EventDataLength=0x7fff -> buggy sz=65532 (truncated)
RESULT: BUGGY - u16 truncation
---PATCHED---
EventDataLength=0x4000 -> patched sz=65536
EventDataLength=0x4001 -> patched sz=65536
EventDataLength=0x6000 -> patched sz=65536
EventDataLength=0x7fff -> patched sz=65536
RESULT: PATCHED - u32 sz, sanity check
```

## Fix

Declare sz as u32 (matching the promoted product) and add a sanity cap (e.g., max 65536). This also closes the kmalloc(0) ZERO_LENGTH_PTR case.

The full git-apply-able unified diff is in `fix.diff`. It applies cleanly
to `/usr/src/sys/dev/raid/mps/mps_sas_lsi.c:128-145` and the patched file compiles cleanly under the
kernel's CFLAGS (validated by an in-guest module build).

## Files

- `harness.c` — userspace replica of the vulnerable logic (u16 truncation table for EventDataLength 0x4000..0x7FFF)
- `build.sh` / `run.sh` — exact build and run commands
- `fix.diff` — standalone git-apply-able fix (validated to apply + compile)
- `run.log` — full unpatched + patched harness output
- `env.txt` — guest environment
