# DF-3681 — igb never terminates its self-re-arming timers at detach (UAF)

## What
igb(4) runs two self-re-arming callouts and tears both down with
`callout_stop()` only — never `callout_terminate()`:

- `sc->timer` — `igb_timer()` (`sys/dev/netif/igb/if_igb.c:1308-1321`) takes
  `lwkt_serialize_enter(&sc->main_serialize)` (blocking) and unconditionally
  re-arms itself at `:1318` (`callout_reset_bycpu(..., hz, igb_timer, sc, ...)`).
- `txr->tx_gc_timer` (one per TX ring) — `igb_txgc_timer()`
  (`:327-350`) re-arms itself at `:349` (`callout_reset(..., 1, ...)`) on the
  try-serialize-failure path (`goto done`).

`igb_stop()` stops them with `callout_stop()` (`:1436`, `:1447`), which per
`sys/kern/kern_timeout.c:1087-1098` "does not interlock against a callout
that is in-progress": a callback that is *currently executing* (or blocked)
can still `callout_reset()` itself after `callout_stop()` returns.
`igb_detach()` (`:742-802`) contains **no** `callout_terminate` for either
timer.

## Race (wide window for sc->timer)
1. CPU1: `igb_timer` fires; blocks in `lwkt_serialize_enter(&sc->main_serialize)`
   (detach holds all serializers via `ifnet_serialize_all`, `:750`).
2. CPU0: `igb_detach` → `igb_stop` → `callout_stop(&sc->timer)` — the callout
   is INPROG, not pending, so nothing is cancelled → `ifnet_deserialize_all`
   (`:763`) → `ether_ifdetach` (`:765`) → resource release (`:773-799`) →
   `igb_free_rings` (`:784`) → `kfree(sc->serializes)` (`:791`).
3. CPU1: acquires the (about-to-be-freed) serializer, runs, and re-arms
   `sc->timer` for `hz` later (`:1318`).
4. One second later the callout fires into freed memory: the callout
   structure lives inside the softc (freed by devclass after detach /
   kldunload), the callback executes `igb_timer` reading freed `sc`,
   `lwkt_serialize_enter` on freed memory, MMIO through the released
   `mem_res` mapping; under `kldunload if_igb` the module text itself is
   unmapped. Use-after-free (read + callout-internal writes on freed slab).

Same class as DF-3669 (ix). Notably, ix(4) received
`callout_terminate(&sc->timer)` at detach (`sys/dev/netif/ix/if_ix.c:693`)
— igb(4) lacks even that mitigation for both timer classes.

## Reproduce / verify
Requires igb hardware (timers only run once the interface is up). The audit
guest has none (`run.log`). Source-level verification only.

## Expected result (on hardware)
`kldunload if_igb` / devctl detach racing a fired `igb_timer`/`igb_txgc_timer`
→ delayed panic or heap corruption in callout internals after the softc/rings
are freed. With the fix, `callout_terminate()` after the serializers are
dropped guarantees no post-detach fire.
