# DF-5724 VERDICT — reproduced (panic-class trap cascade + hard hang), fix validated

## Narrative

`$tabstops` is a raw-settable DDB variable (`sys/ddb/db_variables.c:52`,
`:120-128`). `db_force_whitespace()` (`sys/ddb/db_output.c:74-93`) evaluates
`NEXT_TAB(i) = rounddown(i + db_tab_stop_width, db_tab_stop_width)` and
DragonFly's `rounddown` (`sys/sys/param.h:400`) has no zero guard.

**Variant A — `set $tabstops=0` (stock kernel, live):** accepted silently.
The next `"db> "` prompt leaves a pending trailing space (pos=4, last_non=3);
`db_readline()`'s output-position sync (`sys/ddb/db_input.c:306`) calls
`db_force_whitespace()`, which executes `rounddown(3+0, 0)` -> **fatal trap
18 (integer divide fault) in kernel mode**, RIP `0xffffffff802cba26` =
`db_force_whitespace+0x26` (symbolized via `nm`, `env.txt`). Because the trap
handler itself prints through the same path, the machine enters a **cascade
of 31 identical fatal traps** (`serial.variantA.log`), the kernel stack
descending from `0xfffff801183f7458` to `0xfffff8004f0686d8` (~0x370/trap)
before going silent. ssh dead; only a hard reset recovers. `Fatal trap 18`
count: 31.

**Variant B — `set $tabstops=-8` (stock kernel, live):** accepted silently;
the same prompt-sync enters the whitespace loop with `next_tab = 0 <= pos`
and an inner `while (last_print < next_tab)` that never advances -> **silent
infinite loop with all CPUs stopped** (`serial.variantB.log`: transcript ends
at the prompt; zero traps; ssh dead). The exact `print/d 5` trigger
(`db_printf("%11ld")` leading spaces at column 0) was never even needed — the
prompt's own pending space suffices.

**Controls in-session:** before each `set`, `x/x db_active` prints normally
(tabstops still 8).

**Fix validation (same guest, rebuilt kernel):** `fix.diff` applied to the
guest's `/usr/src` (md5-verified source parity with the audited tree), kernel
rebuilt (`nativekernel`, BUILD_RC=0, installed `#1: Sat Oct 10 17:53:17 UTC
2026`), guest rebooted, identical driver rerun: both variants now print
`tabstops must be >= 1` (db_error longjmp aborts the set before the store),
and the previously-fatal commands (`x/x db_active`, `print/d 5`) work; the
DDB session stays fully alive and `c` continues. Zero fatal traps
(`serial.fixedkernel.log`). Baseline vs patched captured in the same pack.

## Impact

Whole-host unrecoverable freeze/trap-cascade from the DDB console.
DDB entry itself needs root — including **jailed root** via
`sysctl debug.enter_debugger=ddb` (reachability established by DF-2246), so
the realistic ceiling is "jailed root freezes the entire host, survives
nothing less than a hard reset". No memory corruption, no info leak: pure
DoS/panic class. Severity Medium (matches DF-2246's bar), confidence certain.

## Exploit chain

(none — denial of service only)
`jailed root` -> `sysctl debug.enter_debugger=ddb` -> `set $tabstops=0` ->
cascade of fatal trap 18 (`db_force_whitespace+0x26`) eating the kernel
stack -> brick; or `set $tabstops=-8` -> infinite loop in
`db_force_whitespace` with all CPUs stopped -> silent brick.

## Kernel references

- sys/ddb/db_output.c:65 (NEXT_TAB), :74-93 (db_force_whitespace loop/div)
- sys/ddb/db_variables.c:48-53 (raw variable table), :120-128 (unvalidated store)
- sys/ddb/db_input.c:306 (db_readline sync call that fires it)
- sys/sys/param.h:400 (rounddown without zero guard)
- sys/ddb/db_command.c:481-488 (db_error longjmp used by the fix)

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