# DF-4783 verdict — NOT reproduced with faithful workloads; mechanism confirmed by inspection; over-strong harness panics 3/3

## What was tested (guest: DragonFly 6.5-DEVELOPMENT, QEMU 7.2 sdhci-pci + sd-card)

1. **Faithful holder across teardown** (`mmhold.c`: open once, pread the same
   fd forever): 10101 successful reads, then EBADF forever; guest healthy.
   destroy_dev() re-vectors the pinned cdev's ops to dead_dev_ops, so *new*
   post-teardown I/O never reaches `mmcsd_strategy()` — identical to the
   "nvzombie" observation in the DF-4646 nvme pack.

2. **Faithful battery**: 8 holder processes × 10 card-removal/re-insert
   cycles (`mmcrace.ko` action=1/2 == the real `mmc_delete_cards()`/
   `mmc_scan()` paths, driven from a worker kthread because
   `device_delete_child()` self-deadlocks if called from a sysctl handler
   holding sysctllock). All cycles clean; no panic.

3. **Aggressive kernel hammer** (16 kthreads calling `dev_dstrategy()`
   directly, without the cdev reference that all in-tree callers hold):
   **panic in 3/3 fresh boots**, all inside the teardown window —
   `dev_dstrategy+0x1b: movl 0xc(%rax),%r12d` (runs 1-2, freed cdev) and
   `lockmgr_exclusive+0x5d: orl (%r14),%esi` (run 3, MMCSD_LOCK on freed
   memory). Determined afterwards that `dev_dopen()` does not raise the
   cdev sysref, so the rig's "open" never pinned the cdev and these panics
   race a freed cdev — a caller-contract violation no legitimate workload
   performs. They are retained as *evidence of the missing serialization*
   (the teardown genuinely mutates/frees objects the data path is actively
   walking), but they do not establish a reachable primitive, hence the
   honest classification: **not_reproduced**.

## The code race that stands (by inspection, certain at the code level)

`mmcsd_detach()` (mmcsd.c:209-248) vs `mmcsd_strategy()` (mmcsd.c:304-324)
and `mmcsd_open()` (mmcsd.c:286-295):

- strategy resolves `si_drv1` (mmcsd.c:310) → `MMCSD_LOCK` (mmcsd.c:311)
  with zero exclusion against `MMCSD_LOCK_DESTROY` (mmcsd.c:245) and the
  newbus softc free that follows `device_delete_child()` (mmc.c:259,
  sdhci.c:874). A caller stalled between those instructions across the
  free lockmgr()s freed memory (run-3 signature). `si_drv1` is never
  cleared, so the dangling pointer is walked by anything that resolved it
  in time.
- the `suspend > 0` arm (mmcsd.c:312) queues into a consumerless queue
  with no bound (separately filed as DF-4784).
- the queue flush (mmcsd.c:233-239) runs outside the lock — currently safe
  only because both the enqueue-condition check and detach's update of
  running/suspend are under the lock; fragile, and the fix moves it under
  the lock.

Comparison with the reproduced DF-4646 (nvme): nvme's teardown freed
queues its own still-running admin thread and interrupt handlers kept
using (active UAF), while mmcsd's task thread is correctly joined and
devfs's dead-ops re-vector blocks new work — so mmcsd's residual is a
narrow in-flight-stall TOCTOU rather than a guaranteed UAF.

## Threat model

Trigger = card removal / controller hot-unplug / kldunload while I/O is in
flight: physical-access attacker yanking an SD card, or root. Consequence
if the window is hit: lockmgr on freed memory → panic or, with adversarial
heap reuse, bioq corruption (write primitive into freed-softc reuse).
Probability per event: low (window is instructions wide); not hit in 10
faithful cycles on the rig.

## Fix

`fix.diff` mirrors the shape validated for DF-4646: a `gone` flag set under
the lock before the thread kill, an in-flight strategy counter drained
before `disk_destroy()`/`lockuninit()`, clearing `si_drv1` on the raw cdev,
and moving the queue flush under the lock. Not build-validated here because
the faithful baseline did not reproduce (validation would be vacuous).

## Files

`mmcrace.c` (trigger+hammer), `mmhold.c` (faithful holder), `mmio.c`
(userspace multi-thread re-opener), `mmcbang.c` (driver attach/detach
invoker — superseded by mmcrace), `panic-run{1,2,3}.txt`,
`userbat.log`, `run.log`, `fix.diff`.

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