# DF-3825 — asr(4) unbounded polled waits: a transiently wedged adapter hard-hangs the kernel (wait-forever spin inside a critical section, zero-timeout reply polls, unkillable ioctl sleep)

- **File:** `sys/dev/raid/asr/asr.c`
- **Lines:** 1253-1255 (`ASR_reset` — `while (ASR_resetIOP(sc) == 0);`
  inside `crit_enter()`), 1892 (`ASR_initOutBound` —
  `while (*Reply_Ptr < I2O_EXEC_OUTBOUND_INIT_REJECTED);` with **no
  timeout at all**, directly reachable from the `I2OUSRCMD` ioctl at
  :3211-3219), 727-729 (`ASR_queue_s` — no-timeout interrupt poll),
  3499-3523 (`ASR_queue_i` — 1 s `tsleep` loop without `PCATCH`)
- **Class:** CWE-834/CWE-667 — unbounded busy-wait on untrusted device
  state → system hang / unkillable threads
- **Reach:** adapter lock-up (the V1.05 changelog documents the exact
  failure mode this driver still hangs on) or, for the `initOutBound`
  leg, root via `ioctl("/dev/asr0", I2OUSRCMD)`.

## Analysis

1. **`ASR_reset()`** (asr.c:1226-1275) runs under `crit_enter()`; if the
   IOP fails to re-arm it executes

   ```c
   1253:		/* Wait Forever */
   1254:		while (ASR_resetIOP(sc) == 0);
   ```

   an infinite spin — `ASR_resetIOP` itself polls MMIO/DMA with bounded
   delays (asr.c:577-586) but the retry loop never gives up.  Reached
   from `asr_timeout()` (callout, asr.c:1297/1314) and
   `XPT_RESET_DEV`/`I2ORESETCMD`.  A spinning thread inside a critical
   section blocks that CPU's interrupts — the whole system degrades to a
   watchdog hang.
2. **`ASR_initOutBound()`** (asr.c:1854-1929):

   ```c
   1892:		while (*Reply_Ptr < I2O_EXEC_OUTBOUND_INIT_REJECTED);
   ```

   busy-loops on a DMA'd status word with no timeout, holding the
   adapter's interrupts disabled.  Besides boot/`ASR_reset`, this is
   reachable verbatim from user space: `ASR_queue_i()` special-cases
   function `I2O_EXEC_OUTBOUND_INIT` (asr.c:3211-3219) and calls it
   directly.
3. **`ASR_queue_s()`** (asr.c:715-733) polls `asr_intr(sc)` until the
   ccb completes — no deadline; a lost completion spins the caller
   (kernel thread / ioctl) at full tilt.  Every synchronous
   configuration path (LCT, HRT, params, attach INQUIRY) funnels through
   it.
4. **`ASR_queue_i()`** (asr.c:3499-3523) waits with `tsleep(..., hz)`
   but no `PCATCH` and no bound — an unkillable D-state thread per
   outstanding ioctl when the card stops replying (blink-LED check is
   the only exit).

The changelog at asr.c:46-50 ("System locked up if the Adapter locked
up") shows the vendor knew the class; these loops are the remaining
instances.

## Build / Run (guest trigger)

```
cc -O2 -Wall -o asr_ioctl_poll asr_ioctl_poll.c
./asr_ioctl_poll /dev/asr0
```

Expected on hardware: issuing `I2O_EXEC_OUTBOUND_INIT` while the IOP is
deaf wedges the caller in the zero-timeout loop.
Observed on the audit guest: `open("/dev/asr0") → ENOENT` — no I2O HBA
present (root and unprivileged, see `run.log`/`run.2.log`; `env.txt`).

## Verdict

`not_reproduced` — hardware-gated (device absent); source-certain.
