# DF-4086 VERDICT

**Status:** not_reproduced (kernel level) — hardware-gated; **off-by-one
read + conditional OOB write proven at object level on the audit guest**.
**Confidence:** certain (arithmetic + sinks traced line-by-line).

## Why end_idx can equal max_devices

- `mps_mapping.c:1734` `sc->max_devices = sc->facts->MaxTargets +
  sc->max_volumes;` (MaxTargets: U16 IOC facts `mpi2_ioc.h:275`;
  MaxVolumes: U8 `mpi2_ioc.h:282`).
- `:1746-1747` `num_rsvd_entries = 1` when pg8 `RESERVED_TARGETID_0`.
- `:221-235` `_mapping_get_ir_maprange()`: low-volume-mapping ⇒
  `start_idx = 1` (reserved), `end_idx = start_idx + max_volumes - 1`.
- With `MaxTargets == 0`: `max_devices == max_volumes` ⇒
  `end_idx == max_devices` — the loops below run `map_idx <= end_idx`
  and touch `mapping_table[max_devices]`, one entry (32 bytes) past the
  `kmalloc(max_devices * 32)` (`:1393-1394`) allocation.

All four inputs (MaxTargets, IR capability, volume-mapping mode, reserved-id
flag) come from the IOC firmware/pci-attached device; nothing clamps the
range.

## Sinks verified in source

1. `_mapping_get_ir_mt_idx_from_wwid` `:364-368` — `for (map_idx = start_idx;
   map_idx <= end_idx; map_idx++, mt_entry++) if (mt_entry->physical_id ==
   wwid)` → OOB read; if adjacent-heap garbage equals the WWID (fw can retry
   WWIDs), the returned index flows to `:2174-2179`
   (`mt_entry->device_info |= MPS_MAP_IN_USE` — OOB read-modify-write).
2. `_mapping_get_ir_mt_idx_from_handle` `:407-411` — same, on `dev_handle`.
3. `_mapping_get_free_ir_mt_idx` `:456-468` — first pass returns the first
   index whose `device_info` lacks `MPS_MAP_IN_USE`; at `map_idx ==
   max_devices` that is adjacent-heap memory → **returns an OOB index**.
   Second pass can equally return it via `missing_count` (OOB read).
4. `mps_mapping_ir_config_change_event` `:2206-2232` — on volume ADDED /
   VOLUME_CREATED with no matching WWID: `map_idx =
   _mapping_get_free_ir_mt_idx(sc); ... mt_entry =
   &sc->mapping_table[map_idx];` then writes `physical_id` (WWID),
   `channel`, `id`, `dev_handle`, `device_info`, `init_complete` —
   **32-byte OOB write with firmware-controlled fields**.
   `_mapping_update_ir_missing_cnt` `:612-627` then also marks
   `dpm_flush_entry[dpm_idx]` (bounded) — fine.
5. `mps_mapping_check_devices` `:1645-1664` — `for (i = start_idx; i <
   end_idx + 1; ...)` writes `init_complete`/`missing_count` at the OOB
   index; **currently dead code** (declared `mpsvar.h:745`, zero callers —
   the same deadness that neutralizes the DF-3915 twin in mps), noted for
   completeness.
6. `_mapping_check_update_ir_mt_idx` `:2124-2129` — `do { mt_idx++; if
   (mt_idx > end_idx) return 1; mt_entry = &sc->mapping_table[mt_idx]; }
   while (...)` reads `device_info` at the OOB index.

## Verification performed

- Guest `pciconf -l` (env.txt): no SAS HBA ⇒ no in-kernel run possible
  (same hardware gate as DF-1374/DF-1375/DF-3914..3919).
- `harness_df4086.c` on the guest (unprivileged user, cc 8.3): verbatim
  range computation + `<=` walks + the `:2222-2232` event write; guard entry
  `[max_devices]` (canary `0x4141...`) is overwritten with the fw WWID
  `0x57119418BADB00B5` → 32-byte OOB write proven; output identical across
  two runs (`run.log`, `run.2.log`).
- `fix.diff` (clamp `end_idx <= max_devices - 1`) applied to the guest
  `/usr/src` together with DF-4085's bound and the rest of this batch's mps
  fixes; module rebuilt with `-Werror`, `mps.ko` linked (BUILD_EXIT=0,
  `fix_build.log`); `/usr/src` restored pristine afterwards; guest reset
  with clean-source snapshot.

## Exploitability ceiling

Same threat model as the other mps mapping findings (malicious/buggy IOC
firmware or emulated HBA via PCI passthrough): IR config-change event →
32-byte struct write just past `mapping_table` with fw-chosen WWID/handle →
adjacent slab-object corruption → potential kernel code execution. Gated
here only by absent hardware.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
