# DF-1191 — ciss_cam_complete unchecked controller sense_length (heap overflow)

## Verdict
**REPRODUCED (harness) — real bug confirmed by source trace + userspace replica.**
Impact class: heap overflow of `union ccb` (sense_data → cdb_io/msg_ptr → adjacent
heap). No local-unprivileged trigger on the audit guest (no HP Smart Array
controller); trigger requires a malicious/emulated CISS controller returning an
oversized `sense_length`. `uid=0` chain N/A — hardware/firmware-attacker class.

## Mechanism (confirmed `path:line`)
`ciss_cam_complete()` copies controller-supplied sense data into the CAM ccb:

- `sys/dev/raid/ciss/ciss.c:3248` — `bzero(&csio->sense_data, SSD_FULL_SIZE);`
- `sys/dev/raid/ciss/ciss.c:3249` — `bcopy(&ce->sense_info[0], &csio->sense_data, ce->sense_length);`

`ce->sense_length` is a **u8 (0..255)** supplied by the controller in its
`ErrorInfo` struct (`sys/dev/raid/ciss/cissreg.h:120`). `csio->sense_data` is a
`struct scsi_sense_data` of exactly `SSD_FULL_SIZE = 32` bytes. There is **no
`min()`/`imin()`** clamping the copy length, so a `sense_length > 32` overwrites
the fields that follow `sense_data` inside `union ccb` (`cdb_io`, `msg_ptr`) and
the neighbouring heap object. The size is fully controller-controlled (0..255 →
up to 223 bytes past the buffer).

Threat surface: a malicious CISS controller, OR (where a ciss pass-through
`/dev/passN` exists on hardware) an operator-issued command whose CHECK_CONDITION
response the controller pads with an oversized `sense_length`. In all cases the
length is controller-determined, not user-controlled — this is a
malicious-controller bug, not a local-user-controlled write.

## Harness proof (`run.log`)
`harness.c` replicates the `bzero`+`bcopy` against a 32-byte buffer with a 64-byte
canary "neighbour" (standing in for the rest of `union ccb`):

```
sense_length= 32 : in-bounds (overflow into neighbor canary: 0 bytes, ...)
sense_length= 64 : OVERFLOW REPRODUCED (overflow into neighbor canary: 32 bytes, ...)
sense_length=255 : OVERFLOW REPRODUCED (overflow into neighbor canary: 32 bytes, ...)
```

## Why not a live-kernel trigger / no uid0 chain
`ciss` attaches only to HP Smart Array PCI devices (none on the guest → module
never loaded). `ce->sense_length` is set by the controller firmware in its DMA'd
`ErrorInfo`, reachable only through a controller that is present. No
unprivileged syscall path controls it. Hardware/firmware-attacker class; no
local-privesc chain.

## Fix (`fix.diff`)
Clamp the copy length at `ciss.c:3249`:
`bcopy(&ce->sense_info[0], &csio->sense_data, imin(ce->sense_length, imin(SSD_FULL_SIZE, csio->sense_len)));`
`imin` is `static __inline` in `sys/sys/libkern.h:70` (available kernel-wide).
Matches the finding's proposed fix (clamp to `imin(sense_length, SSD_FULL_SIZE, sense_len)`).

## Fix validation
`ciss.ko` rebuilt from patched source (DF-1190/1191/1192 applied) compiled with
`-Werror` and linked — the `imin(...)` type-checks against the `u_int8_t`
operands. `fix_status: not_testable` (no CISS HW for a live trigger; validated
applies + compiles + closes the path by inspection).
