# DF-5071 Verification Verdict

**Severity:** Medium · **Impact class:** dos (unkillable D-state hang,
unbounded queue growth)
**Method:** sink-level reproduction on the stock guest kernel
(DF-4986/DF-5012/DF-5026 house precedent) + fix compile-validation
against the guest's /usr/src.

## Verdict: REPRODUCED (dos), fix VALIDATED (behavioral A/B + amr.ko build)

### The bug (source chain, all lines verified)

Once `AMR_STATE_SHUTDOWN` is set (`amr_pci_shutdown` amr_pci.c:395 or
`amr_rescan_drives` amr.c:466) — or the adapter simply wedges, since amr
has **no timeout/watchdog anywhere** (verified: only a poll-loop timeout
at amr.c:1355 exists, for polled commands) — every bio submitted through
an already-open disk fd is parked on `sc->amr_bioq` forever:

- `amrd_strategy` (amr_disk.c:166-194) checks ONLY `sc == NULL`; it has
  **no** `AMR_STATE_SHUTDOWN` gate — in the same file `amrd_open`
  (amr_disk.c:126-127) refuses new opens with ENXIO in exactly that
  state. Worse, even that lone gate is bypassed whenever another fd holds
  the disk open, because `diskopen()` skips the driver's `d_open` while a
  slice ref is open (`sys/kern/subr_disk.c:1094`) — demonstrated live.
- `amr_submit_bio` (amr.c:407-416) enqueues (`amrvar.h:309`) and calls
  `amr_startio`, then returns 0.
- `amr_startio` (amr.c:1155-1188) calls `(void)amr_bio_command(sc, &ac)`
  — the return value is IGNORED (amr.c:1171) — and gives up when no
  command was built (`ac == NULL`, amr.c:1178): the bio stays queued.
- `amr_bio_command` (amr.c:1240-1241) returns ENOMEM without dequeuing
  when `amr_alloccmd` fails — the steady state on a wedged adapter where
  every command sits busy forever (nothing completes them: completions
  only come from the interrupt → `amr_done` → `amr_complete`
  → `amr_startio`).
- Nothing drains `amr_bioq` on any shutdown/detach path
  (`amr_pci_shutdown` amr_pci.c:387-417, `amr_rescan_drives`
  amr.c:454-485, `amr_free` amr.c:371-400); the comment at amr_pci.c:383
  ("we can assume that the bioq on the controller is empty, as we won't
  allow shutdown if any device is open") is FALSE: `AMR_STATE_OPEN` is
  set only by the CONTROL device open (amr.c:430); `amrd_open` sets
  nothing. At detach the bioq head is `kfree`d with bios still on it
  (feeding the DF-2082 in-flight UAF window).

Consequence: the issuer sleeps in biowait in an **unkillable D-state**,
and the queue grows without bound. Trigger: root `kldunload amr` /
`AMR_RESCAN_DRIVES` ioctl with I/O queued or in flight, or any adapter
wedge/fault. Root-on-amrd wedges the whole machine.

### Reproduction (run.log)

- holder process (fd opened BEFORE shutdown) pread after
  `AMR_STATE_SHUTDOWN` set → `D0/physstr` (biowait);
- **survives `kill -9`** (SIGKILL pends; delivered only when the bio is
  eventually completed);
- released only by the external poke drain (`dmesg: poke -- draining 1
  parked bio(s) with EIO`), process exits with EIO;
- `amr_startup` (amr.c:294-344, `&= ~AMR_STATE_SHUTDOWN` at :338)
  restores normal completion — parking is a direct consequence of the
  missing gate/drain, not of device removal;
- gate asymmetry: fresh open during shutdown with holder → SUCCEEDS
  (subr_disk.c:1094 bypass); fresh open without holder → ENXIO
  (amrd_open :126-127 fires).

### Fixed variant (run_ab.log)

Two hunks only (the ones in fix.diff): (1) `amrd_strategy` fail-fast
mirroring `amrd_open`, (2) drain of queued bios when shutdown is entered.
Result: shutdown entered with 4 incidental bios genuinely parked →
`(fixed) draining 4 parked bio(s) with ENXIO` → the held fd's subsequent
pread returns **immediately** `r=-1 errno=6 (ENXIO)` — no D-state, no
residual process, no accumulation.

### Fix validation

1. Behavioral A/B at sink level (run.log vs run_ab.log): baseline wedges
   unkillably; fixed returns ENXIO immediately.
2. Compile validation (fix_validation.log): `fix.diff` applied to the
   guest's `/usr/src` (amr_disk.c + amrvar.h + amr.c + amr_pci.c);
   `make` in `/usr/src/sys/dev/raid/amr` produced `amr.ko` with `-Werror`,
   0 warnings (patched `amr_disk.o` in the link line). Sources restored
   pristine afterwards (grep marker 0).

### Hardware gate

The real entry needs a MegaRAID adapter (absent on the QEMU guest); the
completion topology is driver-side unconditional control flow, and the
identical shape was sink-level reproduced for mfi (DF-5012) and ips
(DF-5026) before. Impact ceiling: permanent unkillable-hang DoS for every
issuer (whole-system wedge when amrd carries root) on hardware fault,
adapter removal, or privileged rescan/unload.

Guest returned to a clean state (modules unloaded, sources pristine,
no parked bios): `guest_dirty = 0`.

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