# DF-4369 — hpt27xx: hpt_timeout / os_cmddone completion race → use-after-free of PCOMMAND

## What this is

A pass-2 (GLM 5.3) audit finding in `sys/dev/raid/hpt27xx/hpt27xx_osm_bsd.c`:
the per-command timeout `hpt_timeout()` races the completion path
`os_cmddone()`. `os_cmddone()` uses `callout_stop()`, which on DragonFly
explicitly **does not interlock against an in-progress callout**, and then
frees the command (`ldm_free_cmds(pCmd)`) and its extension. If the 20-second
timeout fires on another CPU at the same instant the command completes,
`hpt_timeout()` dereferences `pCmd->priv` after the free — a use-after-free
read that becomes a wild-pointer dereference when the freed PCOMMAND is
immediately recycled (e.g. as a flush command whose `priv` points at a kernel
stack variable).

## Build / Run / Expected

This bug is **hardware-gated**: it requires a HighPoint RocketRAID 27xx SAS
controller (PCI vendor 0x1103) attached and processing I/O.

- There is nothing to build on the audit guest: the driver is already
  compiled into its `X86_64_GENERIC` kernel (`sys/config/X86_64_GENERIC:117`).
- `./run.sh` (or `bash verify_env.sh`) probes the guest and prints:
  kernel/uname, the full PCI device list, and the hpt27xx module state.
- **Expected on real hardware** (not available here): under SMP with I/O that
  completes in the same instant its `HPT_OSM_TIMEOUT` (20 s) deadline expires,
  `hpt_timeout()` reads `pCmd->priv` of a command already released to the LDM
  freelist; if the command block was recycled (flush: `priv = &done` kernel
  stack at hpt27xx_osm_bsd.c:303; internal ldm commands: `priv` per blob),
  `ext->vbus_ext` resolves to a stack/garbage pointer and
  `ldm_reset_vbus(<wild>)` panics the kernel (fatal trap in
  `hpt_timeout`/`ldm_reset_vbus`).
- **Observed on the audit guest**: no HighPoint PCI device exists
  (`pciconf -l` shows only i440FX/PIIX4/bochs-VGA/virtio), so the driver's
  `hpt_probe()` never attaches, `hpt_final_init()` prints
  "no controller detected", no `/dev/hpt27xx` node and no CAM sim are
  created, and the racing code paths are unreachable. See `run.log`.

## Contents

- `VERDICT.md` — full narrative with path:line proof chain and the honest
  verification classification (not reproducible without the controller).
- `race_proof.txt` — annotated source walk of the race.
- `verify_env.sh` / `run.sh` — guest environment probe.
- `run.log` — actual probe output from the audit guest (2026-09-19).
- `env.txt` — guest uname, kernel, module state.
- `fix.diff` — git-apply-able fix (guarded reset under the vbus lock).
- `manifest.json`, `verdict.json`.
