# DF-1919 PoC

Trigger: in an `MRSAS_IOC_FIRMWARE_PASS_THROUGH` ioctl, supply an iovec
with `iov_len = 0x100000008` (or any 64-bit value whose low 32 bits are a
small positive int and whose high 32 bits are non-zero). The driver stores
that into the 32-bit `int ioctl_data_size` (truncation), allocates an 8-byte
DMA buffer, hands the firmware an SGE whose length is 8 (also truncated to
`u32`), and then calls `copyin(iov_base, 8-byte-buffer, 0x100000008)` —
the copyin length is the original 64-bit `iov_len`, NOT the truncated
`ioctl_data_size`. Result: copyin overwrites the kernel heap with
attacker-supplied bytes from a user-mapped 4 GiB+ region, stopping only at
the first unmapped page.

## Preconditions

* An LSI MegaRAID SAS HBA present (mrsas_attach creates the cdev).
* `/dev/mrsas0` is created mode `0660 root:operator`
  (`sys/dev/raid/mrsas/mrsas.c:790-792`), so the caller must be `root` or
  in the `operator` group.

**Phase-6 hard blocker on this guest.** Same as DF-1917/1918 — no
MegaRAID SAS HBA in the QEMU audit guest (verified), and `maxx` is not in
`operator` anyway.

## Build

```
cc -O2 -o harness harness.c
```

## Run

```
./harness
```

## Expected output

For each `iov_len` test vector, the harness prints the resulting
`ioctl_data_size` (what `bus_dma_tag_create` / `bus_dmamem_alloc` see),
the SGE length handed to the firmware (also truncated), the `copyin`
length (the original 64-bit `iov_len`), and the resulting heap overflow =
copyin_len − alloc_size. The `truncated-small` case (0x100000008) shows
the canonical 4 GiB+8 overflow.

## Fix

See `fix.diff`: change `ioctl_data_size` to `bus_size_t`, add an explicit
upper bound (`MRSAS_IOCTL_MAX_DATA_SIZE`, 1 MiB) rejecting anything larger,
and use `ioctl_data_size` (not the raw `iov_len`) as the copyin length so
the two cannot disagree.
