# DF-3733 VERDICT

## Finding
The periodic heartbeat is an MP callout that manages its own locking:

```c
    ciss_attach:   callout_init_mp(&sc->ciss_periodic);          /* ciss.c:429 */
    ciss_periodic: lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);        /* ciss.c:3383 */
                   ... work ...
                   lockmgr(&sc->ciss_lock, LK_RELEASE);          /* ciss.c:3431 */
                   callout_reset(&sc->ciss_periodic, ...);       /* ciss.c:3436  <-- RE-ARM AFTER UNLOCK */
    ciss_free:     lockmgr(&sc->ciss_lock, LK_EXCLUSIVE);        /* caller */
                   callout_stop(&sc->ciss_periodic);             /* ciss.c:1874 */
```

Race: `ciss_periodic` running on CPU1 finishes its work, drops the lock
(ciss.c:3431) and is preempted before `callout_reset` (ciss.c:3436). CPU0
(detach) takes the lock, runs `ciss_free` → `callout_stop()` finds the
callout **not pending** (it already fired) and does nothing; teardown
continues — the lock is even released mid-free for `destroy_dev`
(ciss.c:1902), then `callout_terminate` (ciss.c:1907) and `lockuninit`
(ciss.c:1908) run on a callout that CPU1 subsequently **re-arms**. The
re-armed callout fires ~10 s later into a softc whose lock is uninited and
whose resources are freed (regs released ciss.c:1915+, `ciss_logical` freed
ciss.c:1952+, DMA tags destroyed) → `ciss_periodic` reads
`sc->ciss_cfg->heartbeat` and takes an uninited lock on freed state — a
use-after-free execution with kernel-crash-to-corruption potential.

Secondary exposure on the same path: between ciss.c:1902 (lock release) and
lockuninit (ciss.c:1908), a blocked `ciss_periodic` can acquire the lock and
run against a half-torn-down adapter.

This is exactly the mpt (DF-3672..3678) / arcmsr (DF-3708..3711) lesson:
periodic callouts that self-lock must be converted to `callout_init_lk` so
that stop/reset/handler are serialized by the same lock.

## Reachability
Requires `ciss_detach` (privileged: kldunload / devctl) racing the 10-second
heartbeat tick on a machine with the hardware. No unprivileged trigger —
Low severity, correctness/race class.

## Status
- Source-certain interleaving (the re-arm after unlock and the stop-under-
  lock are unambiguous in the code).
- Runtime: **inconclusive** — no CISS hardware on the guest (env.txt) and
  no meaningful race window without a real controller; not exercised live.

## Fix validation
- `fix.diff` (5 hunks): `callout_init_lk(&sc->ciss_periodic, &sc->ciss_lock)`
  at ciss.c:429; the handler drops its own acquire/release (ciss.c:3383,
  3396, 3431); the attach-time direct invocation (ciss.c:486) now takes the
  lock around the call. With `_lk` semantics, callout_reset/callout_stop and
  the handler are serialized under `ciss_lock`, closing the re-arm race.
- `fix_apply.log`: clean dry-run; `fix_build.log`: `ciss.ko` rebuilt with
  all 7 ciss pass-2 fixes at `-Werror`, link rc=0.

**Bottom line: inconclusive at runtime (hardware absent, race needs
privileged detach); source-certain callout-discipline race; fix
compile-validated.**

## 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.
