# DF-1194 — ciss_init_logical / ciss_free off-by-one (<= vs <)

## Verdict
**NOT REPRODUCED (source-confirmed; hardware-gated).** The off-by-one is real
and unambiguous in the source, but the ciss driver only attaches to HP Smart
Array controllers, absent on this QEMU/KVM guest. No runtime trigger; validated
by line-level source trace + a single-fix kernel build.

## Mechanism
`sc->ciss_logical` is declared `struct ciss_ldrive **ciss_logical`
(`cissvar.h:230`) — a pointer to an array of `struct ciss_ldrive *` pointers.
At `ciss.c:1372-1374` the backing array is allocated as

```c
sc->ciss_logical =
    kmalloc(sc->ciss_max_logical_bus * sizeof(struct ciss_ldrive *),
            CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
```

i.e. with `ciss_max_logical_bus` slots (indices `0..ciss_max_logical_bus-1`).
The very next loop at `ciss.c:1376`, however, runs **inclusive** of the upper
bound:

```c
for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
    sc->ciss_logical[i] = kmalloc(CISS_MAX_LOGICAL * sizeof(struct ciss_ldrive),
                                  CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
    ...
}
```

The final iteration writes one `struct ciss_ldrive *` past the end of the
allocation — a classic off-by-one heap overflow into whatever the slab
allocator places immediately after `ciss_logical`. `ciss_free` at
`ciss.c:1953` repeats the same `<=` mistake, reading the OOB pointer and
calling `kfree` on it during detach: `kfree-of-garbage` (an attacker-controlled
kmalloc target in the same slab bucket would be freed).

This is exactly the kind of off-by-one that INVARIANTS slab poisoning
(`WEIRD_ADDR`/`chunk_mark_allocated`) frequently catches and panics on, even
without an attacker; the bug fires on **every** attach/detach of a controller
with `ciss_max_logical_bus >= 1` (which is the initialized minimum,
`ciss.c:1473`).

## Why not triggered on this guest
Same as DF-1193: no HP Smart Array PCI device is present, so ciss_attach (and
therefore ciss_init_logical / ciss_free) is never invoked. Option (d) of the
PoC-runner procedure.

## Recommended fix (in `fix.diff`)
Change `<=` to `<` in both loops (`ciss.c:1376` and `ciss.c:1953`). One
character each, surgical, matches the loop bound everywhere else in the file
that iterates over `ciss_max_logical_bus` (lines 1039, 1883, 2778, 2873, 3872,
4288 all use strict `<`).

## Build validation
Cumulative kernel build with all 5 fixes applied — `NK_DONE rc=0`, no errors.
See `fix_build.log`.

## Reproduce
```
./build.sh    # no-op (no trigger source for hardware-gated bug)
./run.sh      # no-op (no HP Smart Array controller on guest)
```
