# DF-3729 — ciss_notify_rescan_logical: unbounded ndrives + unchecked LUN_TO_BUS/TARGET → OOB heap read and write

**File:** `sys/dev/raid/ciss/ciss.c:3866` (`ndrives` from the
controller-written `list_size`, **no** `CISS_MAX_LOGICAL` sanity check —
unlike `ciss_init_logical` at ciss.c:1357) and `ciss.c:3896-3912`
(`cll->lun[i]` read past the 15-LUN report buffer; `ciss_logical[bus][target]`
indexed with bus∈[0,255] / target∈[0,255] against rows=
`ciss_max_logical_bus` (typically 1-2) × columns `CISS_MAX_LOGICAL`=15).

**Class:** kernel heap OOB read feeding OOB writes (CWE-125/CWE-787),
firmware-data-driven. Upstream-inherited (FreeBSD has the same walk); the
pass-1 set (DF-1190) fixed only the attach-time sibling.

## Reproduce
```sh
./build.sh && ./run.sh
```

## Expected output
Baseline: 226 OOB reads past the report buffer and 226 OOB row/col index
computations, `[BUG REPRODUCED]`. Fixed replica (`-DFIXED` = clamp ndrives
to CISS_MAX_LOGICAL + validate bus/target): `[FIXED] ... 0 OOB accesses`.

## Trigger (kernel)
A `CISS_NOTIFY_LOGICAL`/status-change (or media-exchange) event makes
`ciss_notify_logical` call `ciss_notify_rescan_logical` (ciss.c:3960/3973),
which issues `REPORT_LOGICAL_LUNS` into a 15-LUN buffer and walks the
firmware-supplied `list_size`. A malicious or buggy controller reply
(list_size larger than the buffer, and/or LUN addresses encoding bus/target
outside the arrays — cissreg.h:509-510) produces the OOB accesses; the
driver then WRITES through the OOB `ld` (cl_update, cl_address,
cl_controller; `ciss_identify_logical` stores kmalloc pointers into
cl_ldrive/cl_lstatus).

## Fix
`fix.diff` (two hunks: clamp + bounds check, mirroring ciss.c:1357's
established pattern). Compile-validated with the other 6 ciss fixes at
`-Werror` (`fix_build.log`); behaviorally validated by the `-DFIXED` run.

## Artifacts
`VERDICT.md`, `harness.c`, `build.sh`, `run.sh`, `build.log`, `run.log`,
`run.2.log`, `run.3.log`, `env.txt`, `fix.diff`, `fix_apply.log`,
`fix_build.log`, `manifest.json`, `verdict.json`.
