# DF-5561 — kdb_trap() longjmp re-entry double-increments db_active; leaked db_active routes every trap into the debugger (permanent all-CPU wedge)

**File:** `sys/platform/pc64/x86_64/db_interface.c`
**Severity:** Medium (panic/debug-path state corruption → system-wide persistent DoS)
**Status:** reproduced (stock kernel, deterministic), fix validated on-guest.

## What to build / run

No compilation is needed for the trigger itself — it is a ddb console
sequence plus one root sysctl as the entry vehicle:

1. Boot the guest with a *writable* serial console (ddb reads commands from
   the console; vm.sh's default `-serial file:` is output-only):
   `serial_vm.sh up` + `serial_writer.py` (host-side rig, both in this pack).
2. `sysctl debug.enter_debugger=ddb` (root, over ssh) → box stops at `db>`.
3. At `db>` (host: `echo '<cmd>' > /tmp/opencode/df-5561-ser.in`):
   - `print *db_active` → **1**
   - `call 0x10()` → ddb's `call` (`db_fncall`, sys/ddb/db_command.c:515+)
     raw-jumps to unmapped 0x10 with **no** `db_nofault` protection →
     kernel-mode T_PAGEFLT *inside* the ddb session.
   - at the re-entered prompt: `print *db_active` → **2** (BUG)
   - `c`

## Expected output (stock kernel) — see serial.baseline.txt

```
db> print *db_active
       1
db> call 0x10()
Fatal trap 12: page fault while in kernel mode
...
kernel: type 12 trap, code=10          <-- kdb_trap() default case (db_interface.c:138)
Stopped at      Debugger+0x7c: ...
db> print *db_active
       2                               <-- double-increment: the longjmp re-entry
db> c                                  re-executed db_active++ (db_interface.c:172)
kernel: type 7 trap, code=2            <-- leaked db_active: the NEXT trap (an AST
Stopped at      0x8008bffdc: ...       on the syscall-return path!) re-enters ddb
panic: stop_cpus() failed              <-- cascades: two concurrent stop masks
Trace beginning at frame ...
kdb_trap() at kdb_trap+0x38f           <-- the nested re-entry, twice on the stack
kdb_trap() at kdb_trap+0x38f
trap_fatal() at trap_fatal+0x2cd
trap() at trap+0x85
Debugger("panic")
```

After this the machine sits in ddb forever; ssh no longer answers
(`Connection timed out during banner exchange`, `vm.sh status` ⇒ down).

## With fix.diff applied — see serial.patched.txt

Same sequence: nested prompt shows `print *db_active` → **1**; after `c`,
`CPU3 restarting CPUs … restarted` and then **silence** — no trap storm, no
`stop_cpus()` panic. Exactly one `kernel: type 12 trap` line (the nested
entry's own print) vs. the stock cascade.

## Note on the post-ddb-exit freeze (control, not part of this bug)

On this QEMU rig, *any* ddb session exit (even `sysctl enter → c` with zero
triggers, db_active correctly back at 0) leaves userland timers frozen
(heartbeat test in VERDICT.md; stock and patched behave identically). That
pre-existing exit-path/rig behavior is orthogonal to DF-5561 — the finding's
baseline signatures (counter=2, trap storm, stop_cpus panic) are what the fix
removes, and they are absent on the patched kernel.
