# DF-3833 — stale completion after bus-reset recovery: trm_Interrupt derefs NULL pActiveDCB/pActiveSRB; trm_SRBdone walks the going list without termination

- File: `sys/dev/disk/trm/trm.c` (pass 2)
- Class: CWE-476 NULL deref / CWE-835 unbounded walk → kernel panic (DoS), hardware-timing-gated
- Severity: Low, speculative (needs a stale chip interrupt in a specific window; sibling path of
  the known DF-2524 which was trm_Disconnect's pActiveSRB)

## Build / Run / Expected
Hardware-gated (env.txt: no Tekram HBA on the audit guest). Trigger on hardware: issue
`camcontrol reset` / bus reset (XPT_RESET_BUS) or provoke an external bus reset while tagged
commands are in flight; the chip raises INT_BUSSERVICE/INT_CMDDONE for an aborted command
after the driver already cleared `pACB->pActiveDCB`.

## Root cause
1. `trm_Interrupt`, trm.c:1337-1345:
        pDCB = pACB->pActiveDCB;
        KASSERT(pDCB != NULL, ("no active DCB"));
        pSRB = pDCB->pActiveSRB;          <- also unchecked against NULL
   Windows where `pActiveDCB` is NULL while the chip can still signal
   INT_BUSSERVICE|INT_CMDDONE:
     - `trm_Disconnect` sets `pACB->pActiveDCB = NULL` (trm.c:2359) and the next command is
       only started later by `trm_DoWaitingSRB`;
     - `trm_reset` → `trm_DoingSRB_Done` completes/frees all going SRBs and clears
       `pActiveDCB` (trm.c:1184-1185) **before** re-enabling interrupts (1176-1178) and
       starting new commands;
     - `trm_ScsiRstDetect` clears `pActiveDCB` (trm.c:2805).
   On a GENERIC kernel (no INVARIANTS — KASSERT compiles to nothing, sys/sys/systm.h:117) a
   stale interrupt in that window panics at `pDCB->pActiveSRB` (NULL+offset read); on an
   INVARIANTS kernel the KASSERT fires — either way, panic.
2. `trm_SRBdone`, trm.c:2718-2729: if the completing SRB is not the list head, the walk
        while (psrb->pNextSRB != pSRB)
                psrb = psrb->pNextSRB;
   has no termination. `trm_RecoverSRB` (trm.c:1141-1160) moves every going SRB to the
   waiting list on external-reset detection, but does NOT clear `pDCB->pActiveSRB`; a stale
   completion routed through `trm_Disconnect`→`disc1`→`trm_SRBdone` then walks off the end of
   the (now empty or reordered) going list and NULL-derefs `psrb->pNextSRB`.
