# DF-2786 — mtx_abort_link stale-state double-unlink (kern_mutex.c)

**Target:** `sys/kern/kern_mutex.c` — `mtx_delete_link()` leaves
`link->state == MTX_LINK_LINKED_EX/SH` set on an already-unlinked link;
the reset to `MTX_LINK_IDLE` happens later in `mtx_wait_link()`
(kern_mutex.c:1023) *outside* `MTX_LINKSPIN`.  A concurrent
`mtx_abort_link()` that acquires `MTX_LINKSPIN` in that window reads the
stale LINKED state and executes the de-link writes
(kern_mutex.c:1095-1096 / :1126-1127)

```c
link->next->prev = link->prev;
link->prev->next = link->next;
```

through the victim's dangling `next`/`prev` — writing into whatever the
stale neighbors are by then (in the only in-tree caller, NFS
`nfs_hardterm()` → `rep->r_link`, the neighbors are other `nfsreq`
r_link objects that may already be freed and reused), and poisoning the
live circular wait queue.

## Files

* `mtx_abuse.c`   — KLD storm harness (final version: v6; see header)
* `Makefile`      — kmod Makefile (build inside `/usr/src/sys/modules/`)
* `build.sh`      — build commands (as executed on the guest)
* `run.sh`        — run commands (as executed on the guest)
* `build.log`     — full compiler output of the successful build
* `run.log`       — decisive console output (baseline + control + real)
* `env.txt`       — guest environment
* `fix.diff`      — verified minimal fix (state termination under LINKSPIN)
* `VERDICT.md`    — full narrative
* `verdict.json`  — machine verdict
* `manifest.json` — artifact catalog

## Build (on the DF guest, /usr/src present)

```sh
mkdir -p /usr/src/sys/modules/mtxabuse
cp mtx_abuse.c Makefile /usr/src/sys/modules/mtxabuse/
cd /usr/src/sys/modules/mtxabuse
env MAKESYSPATH=/usr/src/share/mk SYSDIR=/usr/src/sys make obj
env MAKESYSPATH=/usr/src/share/mk SYSDIR=/usr/src/sys make
cp /usr/obj/usr/src/sys/modules/mtxabuse/mtxabuse.ko /root/
```

## Run

```sh
sysctl -w debug.debugger_on_panic=0
kenv mtxabuse.duration=300          # seconds; add mtxabuse.noabort=1 for control
kldload /root/mtxabuse.ko
# watch the serial console / dmesg for:
#   mtxabuse: PHASE1 ... NO-ABORT baseline    (must be clean)
#   mtxabuse: PHASE2 aborters engaged        (aborts start)
#   mtxabuse: CORRUPTION: kernel wrote retired link <p> next=... prev=...
#     ^ positive: kernel wrote into a retired (== freed in production) mtx_link
#   mtxabuse: SUMMARY ... CORRUPT=N
kldunload mtxabuse
```

## Success criterion

`CORRUPT > 0` (and/or `mtxabuse: CORRUPTION:` console lines, an INVARIANTS
KKASSERT in `mtx_chain_link_ex/sh`, or a traced write-fault panic in
`mtx_abort_link`), with the `noabort=1` control run staying `CORRUPT=0`.
