# DF-1192 — ciss_filter_physical negative bus index (OOB read+write)

## Verdict
**REPRODUCED (harness) — real bug confirmed by source trace + userspace replica.**
Impact class: negative array index → OOB kernel-pointer read then controlled OOB
write. No local-unprivileged trigger on the audit guest; trigger requires a
malicious/emulated CISS controller. `uid=0` chain N/A — hardware/firmware-attacker.

## Mechanism (confirmed `path:line`)
`ciss_filter_physical()` (called from `ciss_init_physical`) maps each physical
LUN's `extra_address` into the `ciss_physical[][]` array:

- `sys/dev/raid/ciss/ciss.c:1556` — `bus = CISS_EXTRA_BUS2(ea) - 1;`
- `sys/dev/raid/ciss/ciss.c:1557` — `target = CISS_EXTRA_TARGET2(ea);`
- `sys/dev/raid/ciss/ciss.c:1558` — `sc->ciss_physical[bus][target].cp_address = cll->lun[i];`
- `sys/dev/raid/ciss/ciss.c:1559` — `sc->ciss_physical[bus][target].cp_online = 1;`

`CISS_EXTRA_BUS2` (`cissreg.h:63`) extracts bits 24..29 → **0..63**, then the
code subtracts 1 (CISS firmware numbers physical buses from 1). The preceding
filter (`ciss.c:1539-1541`) rejects only `BUS3 != 0`, `TARGET3 != 0`, and
`MODE2 == 3` — it does **not** reject `BUS2 == 0`. When `BUS2 == 0`:
`bus = 0 - 1 = -1` (the `bus` local is `int`, `ciss.c:1420`), and
`sc->ciss_physical[-1][target]`:
1. reads the pointer one slot **before** the `ciss_physical[]` row array (an OOB
   kernel-pointer read), and
2. writes `cp_address` / `cp_online` **through** that pointer — a controlled
   write to whatever it references.

`ciss_physical` is sized `ciss_max_physical_bus` rows × `CISS_MAX_PHYSTGT`(256)
cols (`cissvar.h:171`, `ciss.c:1495-1503`). `target` (0..255) is always in range,
but `bus` is never validated against `[0, ciss_max_physical_bus)`.

## Harness proof (`run.log`)
`harness.c` replicates the filter + index with the real macros, a benign
`BUS2=2` (→ bus=1, in-range) and a malicious `BUS2=0` (→ bus=-1). The malicious
LUN **passes the filter** and computes a negative index:

```
[malicious] BUS2= 0 target= 5 -> index bus=-1 (valid 0..3) target=5
[benign   ] BUS2= 2 target= 5 -> index bus=1 (valid 0..3) target=5
[BUG REPRODUCED] malicious LUN PASSES the filter and indexes ciss_physical[-1][5]
```

(The first harness revision had a return-value sentinel collision: `bus=-1` was
mistaken for the "filtered" sentinel `-1`. Fixed by using a distinct status code;
the bug itself was correctly computed in both revisions.)

## Why not a live-kernel trigger / no uid0 chain
`ciss` attaches only to HP Smart Array PCI devices (none on the guest). The
`extra_address` comes from the controller's `REPORT_PHYSICAL_LUNS` DMA reply at
probe time — not reachable from any unprivileged syscall. Hardware/firmware-
attacker class (note `AC:H` in the CVSS reflects this); no local-privesc chain.

## Fix (`fix.diff`)
Validate `bus >= 0 && bus < ciss_max_physical_bus && target < CISS_MAX_PHYSTGT`
before indexing, at `ciss.c:1557`. One logical change; compiles cleanly.

## Fix validation
`ciss.ko` rebuilt from patched source (DF-1190/1191/1192 applied) compiled with
`-Werror` and linked; new "physical device %d has out-of-range address" string
present. `fix_status: not_testable` (no CISS HW for a live trigger).
