# VERDICT - DF-4271 (callout_stop does not interlock with in-progress, self-re-arming wb_tick)

**Status: untested** - no W89C840F NIC in the guest (env.txt); the race is
established from the DragonFly callout API contract, which is explicit:

> sys/kern/kern_timeout.c (callout_stop, non-lock-aided callouts):
> "Stops a callout if it is pending or queued, does not block.
>  This function does not interlock against a callout that is in-progress."

wb's callout is plain `callout_init()` (if_wb.c:715) — non-lock-aided.

## Why the race is real

- wb_tick (:1191-1201) *self-serializes* (lwkt_serialize_enter at :1197) and
  *self-re-arms* (callout_reset at :1199) — both under the serializer.
- wb_stop() runs under the serializer too (from wb_init/ioctl/intr/detach)
  and issues only `callout_stop()` (:1590), which by contract cannot wait for
  a callback that is blocked at :1197 waiting for the very serializer the
  stopper holds.
- Detach releases the serializer at :843 and continues teardown
  (ether_ifdetach, miibus child deletion at :848-849, resource release,
  softc free by newbus after device_detach returns).
- The pending callback then proceeds: mii_tick on a deleted/being-deleted
  miibus child, and callout_reset re-arming a timer embedded in memory that
  is about to be (or already is) freed. The re-arm guarantees the UAF repeats
  every hz until the freed callout state happens to be overwritten.

## Impact

Use-after-free (read + indirect call chain through freed softc) after driver
detach on hardware-bearing systems; privileged trigger (kldunload/device
removal). Severity Low: small window, privileged trigger, hardware-gated —
but the consequence is an unbounded repeating UAF, not a one-shot.

## Fix validation

Not possible on this guest (no hardware). fix.diff adds the drain on the
correct side of the serializer release; draining while holding the serializer
would self-deadlock (wb_tick needs the serializer to finish), hence the
placement after :843.

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