# VERDICT — DF-4057 (et_stop sync callout_stop under serializer vs et_tick blocking acquire)

**Status: reproduced** — in the **production handlers themselves**
(`et_stop`/`et_tick` resolved from /boot/kernel/kernel and dispatched;
strictly stronger than the DF-3715 em / DF-4025 re / DF-4046 stge /
DF-4051 nfe family verifications, which used protocol replicas) —
**and fix validated** on a rebuilt kernel.

## Mechanism (all path:line verified on this kernel)

- `et_stop()` runs under `ASSERT_SERIALIZED(ifp->if_serializer)`
  (:553) and its FIRST action is the synchronous
  `callout_stop(&sc->sc_tick)` (:555). Sync semantics:
  `_callout_cancel_or_stop(..., sync=1)` → `ssleep(c, &c->spin, 0,
  "costp", 0)` at sys/kern/kern_timeout.c:920 — waits for an INPROG
  callback to finish.
- `et_tick()` starts with the BLOCKING `lwkt_serialize_enter`
  (if_et.c:2070) and re-arms itself UNCONDITIONALLY before exiting
  (:2080).
- Every production stopper holds the serializer while calling
  et_stop: et_detach:389-390, et_shutdown:427-428, et_ioctl
  SIOCSIFFLAGS down (:1140/:1154), and et_init:1093 (whose first
  statement is et_stop — reachable from SIOCSIFMTU :1183 and the
  watchdog :1268).

## What ran (baseline, stock kernel #0)

1. `callout_init(&sc->sc_tick)` (as et_attach:244), real serializer,
   fake-mii softc; armed the **real `et_tick`** via
   `callout_reset(sc_tick, 1, p_et_tick, sc)` (production arms at hz
   via et_init:1121; 1 tick for determinism).
2. Took the serializer (the stopper role), yield-polled until
   softclock dequeued the tick — `CALLOUT_INPROG` (kern_timeout.c:567)
   latched in 14 ms, the tick parked on `lwkt_serialize_enter`.
3. Dispatched the **real `et_stop(&df_sc)`**.

Console ends at the dispatch marker; `et_stop` never returned.

```
    -1 B1  slize   0.0 (softclock 1)           <- REAL et_tick parked in
1101  D1  costp   0.0 sysctl -w kern.dfet.go=4  <- REAL et_stop parked in
```

- softclock 1 = that CPU's ENTIRE callout subsystem blocked inside the
  real `et_tick` (wchan `slize`), INPROG latched;
- the stopper asleep in `costp` — the sync `callout_stop` wait inside
  the real `et_stop`;
- permanent at +5 s resample; interface serializer never released;
  the sysctl caller unkillable (D-state, kernel);
- guest could not be shut down cleanly afterwards (host force-killed
  QEMU), matching the proven family siblings.

## Rig iteration notes (attempts)

1. v1 armed the tick then busy-`DELAY`-polled for INPROG — never
   latched: a busy loop starves the same-CPU softclock thread (lwkt
   threads do not preempt each other), rig bug, no production
   conclusion drawn from it.
2. v2 polls with `DELAY(1000); lwkt_yield();` — deadlock reproduces
   in ~14 ms (run.log).
3. v3 fixed-kernel run (below).

## Fix validation (kernel #1, Oct 14 2026, same tree + fix.diff)

fix.diff breaks the blocking edge in `et_tick`:
`lwkt_serialize_try` + skip-and-retry-next-tick instead of the
blocking acquire, re-arm gated on `IFF_RUNNING` (et_stop clears it at
:572). Identical rig on the rebuilt kernel:

| scenario | baseline (#0) | fixed (#1) |
|---|---|---|
| stopper vs parked tick | permanent AB-BA: D1/costp vs B1/slize, et_stop never returns | tick no longer parks (try fails in µs, returns; INPROG never latches); **real et_stop RETURNED** with the retry-tick chain live — `S4: REAL et_stop RETURNED - NO DEADLOCK` |

fix_status: **fixed** (baseline_reproduced=1, patched_reproduced=0).

## Impact

Permanent kernel deadlock from ordinary interface lifecycle activity
(ifconfig down / MTU change / watchdog / detach / shutdown) racing the
1 Hz tick: two kernel threads wedged forever, the interface serializer
never released, one CPU's callout subsystem (tsleep timeouts et al.)
starved. Local DoS once the driver is live on hardware; family
mechanism identical to the four already-proven siblings. Severity
Medium stands.

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