# DF-4059 — amr_done trusts the completion list: id 0 → amr_busycmd[-1] wild
# pointer; mb_nstatus > 46 → stack overread disclosed via "bad slot" prints

**Status: REPRODUCED** (panic + controlled OOB write + 209-byte kernel stack
disclosure) — production-handler KLD dispatch rig, no MegaRAID hardware
needed. Fix validated on a rebuilt kernel. See `VERDICT.md`.

## What runs

`dfamr_rig.c` (KLD, root-only `/dev/dfamr0`) fabricates the post-attach
softc of a std-firmware amr controller with REAL bus_dma (mailbox64 / s-g
table / ccb array exactly as `amr_pci.c` allocates them), REAL locks, the
production queue setup and the production std handler trio, then dispatches
the shipped kernel's own code: `amr_done` (global link), `amr_start`,
`amr_std_get_work`, `amr_std_poll_command`, `amr_std_submit_command`
(nm-resolved, objdump prologue-verified). The "card" is a memory register
file + completions written into the real DMA mailbox; `rig_get_work` wraps
production `amr_std_get_work` only to model the card-side interrupt-line
drop. Command clusters are a verbatim copy of `amr_alloccmd_cluster`
(gcc-8.3 inlined that symbol into `amr_attach`).

## Build (on the audit guest, from repo root)

    findings/poc/DF-4059/build.sh        # scp + make + cc dfamr_ctl

## Run

    # baseline boot A: controlled write + stack disclosure + DF-4060 finale
    ./dfbsd-qemu/vm.sh run_root 'cd /root/rig && kldload ./dfamr_rig.ko && \
        ./dfamr_ctl prime && ./dfamr_ctl offs && ./dfamr_ctl magic && \
        ./dfamr_ctl b && ./dfamr_ctl leak 2 && ./dfamr_ctl leak 7 && \
        ./dfamr_ctl tmo 0 && ./dfamr_ctl late'
    ./dfbsd-qemu/vm.sh run_root 'cd /root/rig && ./dfamr_ctl tmo 1'   # panics
    # baseline boot B: idle-controller id-0 panic
    ... kldload, prime, offs, magic ...
    ./dfbsd-qemu/vm.sh run_root 'cd /root/rig && ./dfamr_ctl a'       # panics
    # fix validation (after applying fix.diff + nativekernel + reboot):
    ./dfbsd-qemu/vm.sh run_root 'cd /root/rig && kldload ./dfamr_rig.ko && \
        ./dfamr_ctl prime && ./dfamr_ctl offs && ./dfamr_ctl magic && \
        ./dfamr_ctl b && ./dfamr_ctl leak 2 && ./dfamr_ctl tmo 1 && \
        ./dfamr_ctl late && ./dfamr_ctl a && uptime'                  # all benign

## Expected results

* baseline `a`: `panic: amr: slot 0 not busy?` (amr_done+0x134)
* baseline `b`: NULL store at softc+3088+8*slot, atomic decrement at
  softc+5128 (1208 bytes past the 3920-byte softc), mb_status stored into
  the live `amr_busycmd[0]` pointer — guest survives
* baseline `leak`: 255 "bad slot %d" prints disclosing 209 stack bytes past
  the 82-byte mailbox (kernel heap pointers, caller frame patterns; bytes
  differ between call depths 2 and 7)
* patched: `bad completion id 0`, `excessive completion count 255`, 46
  entries max, zero stores, zero disclosure, guest alive

## Fix

`fix.diff` (git-apply clean): clamp the completion loop to
`nitems(mbox.mb_completed)` and reject completion id 0 in `amr_done`.
