# DF-3737 — VERDICT

**Status: inconclusive (source-certain, runtime hardware-gated) — same
convention as the em(4) twin DF-3714.  reproduced=0, impact=none on this
guest.**

## Reproduced what, and why not more
Guest has no emx hardware (env.txt: `kldload if_emx` loads the module, no
device attaches).  The walk math was replicated and run on the guest
(`run.harness.log` section [C]): with `num_tx_desc=512`,
- raw TDH `0x1000` (out-of-range): 4,194,304 iterations / 8192 full ring
  wraps without termination (capped; the kernel loop is uncapped);
- raw TDH `0xFFFFFFFF` → `int tdh = -1`: same unreachable terminator;
- in-range TDH=100: normal cleanup.

The kernel-side consequence chain is source-certain:
1. `emx_tx_collect()` — sys/dev/netif/emx/if_emx.c:2808-2868 — reads TDH at
   :2817 into `int tdh`, no range check.
2. `while (first != tdh)` (:2832) frees each `tx_buf[first]` via
   `emx_free_txbuf()` (bus_dmamap_unload + m_freem, :391-401) — after one
   full wrap every TX buffer is freed while the device may still own the
   descriptors (DMA-after-free window; on a truly-removed device harmless,
   on a flapping/faulty one it is a live primitive).
3. `KKASSERT(num_avail < tdata->num_tx_desc)` (:2835) panics INVARIANTS
   builds as soon as `num_avail` reaches the ring size; production builds
   keep spinning with the TX serializer held → every ifsq/ifconfig/watchdog
   path on that ring blocks forever (system degradation, effectively
   irreversible without reboot).

Callers: `emx_start` fallback (:1116, :1130), `emx_tx_intr` → `emx_txeof`
boundary GC via `emx_try_txgc` (:412-424), `emx_txgc_timer` (:444),
`emx_tx_purge` from the LSC interrupt (:2888).

## Threat model
Requires a faulty NIC or surprise removal (hot-unplug, flaky PCIe link) —
not attacker-forgeable by an unprivileged local user alone, but hotplug
removal is a routine operator action.  Severity Low (matches DF-3714).

## Fix
`fix.diff` (git-apply clean): bail out of `emx_tx_collect()` when
`(uint32_t)tdh >= tdata->num_tx_desc` instead of walking toward an
unreachable index.  Cannot be runtime-validated without hardware →
`fix_status: not_testable`.

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