# VERDICT — DF-4398

**Status: inconclusive (hardware-gated)** — the audit QEMU guest has no 3ware
controller (vendor 0x13c1), so the path cannot be executed there. The code-level
violation is certain; only the race exploitation needs the HBA.

## Why this is a real bug (line-by-line)

1. `tws_err_complete()` (`tws_cam.c:519-530`) dispatches `TWS_SCSI_IO_REQ` error
   completions to `tws_scsi_err_complete(req, hdr)`.
2. `tws_scsi_err_complete()` (`tws_cam.c:549-603`):
   ```c
   591:  ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
   592:  lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
   593:  xpt_done(ccb);
   594:  lockmgr(&sc->sim_lock, LK_RELEASE);
   596:  callout_stop(req->ccb_ptr->ccb_h.timeout_ch);   /* AFTER xpt_done! */
   ```
3. `xpt_done()` (`sys/bus/cam/cam_xpt.c:4891-4926`) queues the ccb on
   `sim->sim_doneq` and raises `setsoftcambio()`; the cambio SWI then runs the
   periph done routine (`dadone` → biodone → `xpt_release_ccb`) with NO reference
   held by the SIM. After :593 the driver no longer owns the ccb.
4. Between :594 (sim_lock released) and :596 the SWI on another CPU can complete
   and recycle the ccb. `req->ccb_ptr->ccb_h.timeout_ch` is then (a) freed memory
   (periph teardown: `xpt_free_ccb`) or (b) the *new* owner's callout.
   `callout_stop()` on either is a UAF / spurious cancellation of an unrelated
   in-flight transaction's timeout.
5. Contrast the correct order used by the same file:
   `tws_scsi_complete()` :365 (`callout_stop`) → :371 (`xpt_done`), and
   `tws_drain_busy_queue()` :627 → :634.

## Trigger / threat
Any unprivileged disk I/O hitting a unit error (medium error, reset unit attention,
reservation conflict — anything the firmware reports as an error response) while the
cambio SWI is active. Ordinary load; no malicious input required beyond what makes
a disk return errors — but it IS a pure race (window of a few instructions), so
practical frequency is low per event, recurring across every error completion.

## Exploit chain
Not developed — requires the physical HBA. Realistic ceiling: kernel memory
corruption via `callout_stop` on freed/reused callout state (panic-class), or
denial-of-service via silently un-timed CAM transactions.

## Fix validation
Not testable without the controller (`fix_status: not_testable`); fix.diff moves
`callout_stop` before the status mutation / `xpt_done`, matching `tws_scsi_complete`.

## Environment
- Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 (X86_64_GENERIC) x86_64, no 3ware HBA,
  no /dev/tws*, tws not loaded (see env.txt).

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