# DF-0236 — Driver callbacks (`wdog_fn`) invoked under global spinlock w/ interrupts disabled

**Verdict: REPRODUCED (source-level) / LATENT on this guest.**
**Impact: DoS / latency** — a sleeping/stalling driver callback deadlocks `wdogmtx` and stalls
the system; **not** memory corruption, no escalation chain.

## The bug

`sys/kern/kern_wdog.c`, `wdog_reset_all()`:

```c
90: static void
91: wdog_reset_all(void *unused)
92: {
...
96:     spin_lock(&wdogmtx);                 /* global spinlock, raises IPL */
97:     if (LIST_EMPTY(&wdoglist))
98:         goto done;
99:     LIST_FOREACH(wd, &wdoglist, link) {
100:        period = wdog_reset(wd);          /* -> wd->wdog_fn(wd->arg, wd->period) */
...
104:    if (wdog_auto_enable) {
105:        callout_reset(&wdog_callout, min_period * hz / 2, wdog_reset_all, NULL);
106:    }
...
111:    spin_unlock(&wdogmtx);
```

`wdog_reset(wd)` (line 87) calls `wd->wdog_fn(wd->arg, wd->period)` — arbitrary driver code
— while `wdogmtx` is held and interrupts are disabled (spin_lock raises IPL). Any callback
that sleeps, blocks on a lock, or performs slow MMIO will:
- deadlock the global `wdogmtx` (other CPUs hitting `wdog_register`/`wdog_unregister`/the
  sysctls spin),
- spike interrupt-disabled latency system-wide,
- and the self-rescheduling `callout_reset(&wdog_callout, ..., wdog_reset_all, ...)` re-enters
  the same locked-callback path.

## Reachability on this guest (LATENT)

Same as DF-0234: the only `wdog_register()` callers are `amdsbwd.c` and `ichwd.c`, neither
present on this QEMU guest. `wdoglist` is empty, so `wdog_reset_all` early-returns and no
callback is ever invoked. The locking defect is real and confirmed by trace; it is **latent**
until a watchdog driver registers.

## The fix

`fix.diff` snapshots the registered watchdog pointers into a small array **under** the
spinlock, then `spin_unlock()`s before invoking any `wdog_fn`, then re-acquires the lock only
to update `wdog_auto_period` and arm the callout. This keeps list traversal consistent while
guaranteeing driver callbacks run lock-free.

## Kernel refs
- `sys/kern/kern_wdog.c:96` — `spin_lock(&wdogmtx)`
- `sys/kern/kern_wdog.c:99-100` — `wdog_reset()`→`wdog_fn()` called under the lock
- `sys/kern/kern_wdog.c:87` — `wdog_reset` invokes `wd->wdog_fn`
- `sys/dev/misc/amdsbwd/amdsbwd.c:519`, `sys/dev/misc/ichwd/ichwd.c:593` — only registrants
