# DF-5722 — Resuming DDB entered from interrupt context panics the kernel

**Severity: Low (root-console trigger; deterministic kernel panic — any
attempt to debug interrupt-path code with breakpoints crashes the box)**

Setting a DDB breakpoint in any code that runs in interrupt context (e.g.
`b hardclock`) and then continuing (`c`) deterministically panics on
resume:

```
panic: td_critcount is/would-go negative! 0xfffff8008f313f00 -1
cpuid = 0
Trace beginning at frame 0xfffff801154ab548
crit_panic() at crit_panic+0x2f 0xffffffff80672cff
crit_panic() at crit_panic+0x2f 0xffffffff80672cff
crit_exit_wrapper() at crit_exit_wrapper+0x3c 0xffffffff806734ac
```

Reproduced 3/3 boots (with variations: + software watchpoint, + invisible-
step roundtrip, and the minimal single-session recipe). Thread-context DDB
sessions on the same kernel resume cleanly (multiple controls, incl. a
breakpoint hit in `sys_kill` resumed with `c` → machine alive), so the
trigger is specifically the *interrupt-context* session.

## Minimal recipe (run4-minimal-panic.serial.log)

```
db> b hardclock
db> c
CPU0 restarting CPUs: 0x0000000000000000
 restarted
CPU0 stopping CPUs: 0x00000000
 stopped
Breakpoint at   hardclock:      pushq   %rbp
db> d hardclock
db> c
CPU0 restarting CPUs: 0x0000000000000000
 restarted
panic: td_critcount is/would-go negative! 0xfffff8008f313f00 -1
```

One DDB session, entered from the clock-interrupt path via the INT3, no
step-over, no watchpoint, no other state. The panic fires as the session
exits (`crit_exit()` at db_interface.c:201 → `crit_exit_wrapper()` →
`_crit_exit` → `crit_panic`, sys/kern/lwkt_thread.c:1766-1781): the
thread's `td_critcount` was decremented once too often across the session.

## Bisect matrix (all on the same stock kernel)

| # | session context | sequence | result |
|---|-----------------|----------|--------|
| E1-UP | thread (sysctl Debugger) | enter, `c` | ALIVE |
| E2 | thread | enter, `s`, `c` (TF roundtrip) | ALIVE |
| run5a | thread | `b sys_kill`, `c`, hit, `c` | ALIVE |
| run5b | thread | `b sys_kill,0`, `c`, hits | stops each hit, ALIVE |
| run2 | thread | `watch ticks`, `c` | ALIVE (watch inert: DF-5721) |
| run1 | **interrupt** (hardclock bp) + watch | 2 sessions + watch + `c` | **PANIC** |
| run3 | **interrupt** (hardclock bp) | 2 sessions (with invisible step), `c` | **PANIC** |
| run4 | **interrupt** (hardclock bp) | 1 session, `d`, `c` | **PANIC** |

db_run.c's engine executes identical, context-agnostic code in every row
(state captured live: `db_run_mode` transitions, `rfl` TF-clear at every
stop, DR registers idle) — the defect is in the machine layer's crit
accounting across `kdb_trap()` for interrupt-context sessions
(`sys/platform/pc64/x86_64/db_interface.c:160-201` crit_enter/crit_exit,
in interaction with the interrupt entry/exit paths'
`TD_CRITCOUNT` bookkeeping, `ipl.s`/`exception.S`/interrupt stubs).

Filed from the sys/ddb/db_run.c pass-2 audit (where it was discovered and
characterized via db_run.c's step/continue/breakpoint machinery); the
fix owner is db_interface.c / ipl.s.

## Threat model

Requires a DDB breakpoint in interrupt-context code — console/root only
(unprivileged reachability probes all negative, see DF-5721 pack).
Not an escalation; it is a debugger-robustness defect: any root operator
who sets a breakpoint in a clock/interrupt/ITHREAD path gets a guaranteed
panic + crash dump + reboot instead of a debugging session. Three crash
dump sets were taken on the guest (/var/crash info.0-2, kern.0-2,
vmcore.0-2) for offline analysis.

## Files

- `run4-minimal-panic.serial.log` — minimal recipe + panic
- `run5-threadctx-control.serial.log` — thread-context controls (alive)
- `up-panics.fullserial.log` — full serial history (all runs on final boot)
- `panic.watch.serial.log` — run1 (watch + interrupt sessions) panic
- `fix.diff` — defensive kdb_trap critcount save/restore
- `verdict.json` / `manifest.json`

## Reproduce

1. `./../DF-5721/serial_vm1.sh up` (UP guest — on SMP guests the resume
   path wedges earlier in stop_cpus/restart_cpus, DF-5720 lead, and the
   recipe does not complete)
2. `ssh -F dfbsd-qemu/config dfbsd 'sysctl debug.enter_debugger=ddb' &`
3. On serial: `b hardclock`, `c`, wait for "Breakpoint at hardclock",
   then `d hardclock`, `c` → panic + dump + auto-reboot.
