# DF-2946 — VERDICT

**Status: reproduced** (impact: panic — boot-time kernel divide fault; single-variable, pristine guest)

## What was run

Stock guest, kernel `DragonFly 6.5-DEVELOPMENT #0` (INVARIANTS build,
X86_64_GENERIC, 6 vCPU, 4 GB). Single change: one line appended to
/boot/loader.conf:

    kern.stathz="0"

then `shutdown -r now`.

## What happened (vs. what was predicted)

Predicted: `1000 / freq` (kern_systimer.c:271, SYSTF_MSSYNC path, or
`fromhz()` at kern_cputimer.c:199) traps during `initclocks_other()`
(SI_BOOT2_POST_SMP).

Observed (dfbsd-qemu/boot.log, full excerpt in panic.txt): the kernel boots
through init_param1 without complaint (kern.stathz=0 is merely assigned —
subr_param.c:202 has no validation), gets through SMP/MI-interrupt
initialization ("Initialize MI interrupts for 6 cpus"), and dies with:

    Fatal trap 18: integer divide fault while in kernel mode
    cpuid = 0; lapic id = 0
    kernel: type 18 trap, code=0
    CPU0 stopping CPUs: 0x0000003e
    Stopped at      -0x7f9a53d9:    idivq   %r12,%eax
    db>

`idivq` = the 64-bit signed division of the period computation; the boot
position matches `initclocks_other()` exactly (it runs right after MI
interrupt init for all CPUs, before userland). Guest sits in DDB; ssh never
comes up; `vm.sh status` → down. Reproduced on the first attempt; single
variable planted (loader.conf otherwise untouched).

## Why it is a finding and not a duplicate

* DF-0173 covers `kern.hz=0` → division *inside init_param1*
  (subr_param.c:204-207: `ustick`/`nstick`/`ntp_default_tick_delta`).
  With `kern.stathz=0` alone, hz stays 100, those divisions succeed, the
  system passes init_param1 — and dies later in the systimer subsystem.
* DF-2915/2916/2917 are sleepq/systimer *API* defects, not clock-tunable
  validation.
* The codebase itself knows stathz can be zero — `sysctl_kern_clockrate`
  exports `stathz ? stathz : hz` (kern_clock.c:1337) — but the systimer
  registration path (kern_clock.c:439) passes it unguarded.

## Trust boundary / severity

Boot-tunable (loader.conf / loader prompt / console) — requires root or
boot-loader control, identical to DF-0173 (rated Low). No post-boot or
unprivileged write path exists (`kern.stathz` has no runtime sysctl;
maxprocperuid is RW but stathz is not). Ceiling: unbootable system.
Rated **Low** (local boot DoS, privileged trigger), consistent with DF-0173.

## Negative results worth recording

* `kern.nbuf="-1048576"` was planted first-hand and did **not** break boot:
  every nbuf cap in cpu_startup (machdep.c:424-458) compares `long nbuf`
  against unsigned `vm_offset_t` expressions, so the negative value is
  promoted to a huge unsigned, "capped due to kvm" then "due to physmem",
  and the system boots with a sane positive nbuf (129940 on this guest,
  warnings in boot.log). The apparent negative-nbuf valloc-corruption
  hypothesis is refuted on pc64 (same unsigned arithmetic in vkernel64
  autoconf.c:156-158 rescues it there too).
* `MSGBUFSIZE`/msgbuf sizing: compile-time only (`opt_msgbuf.h`), no kenv
  tunable anywhere — not attacker-influenced in this threat model.
* `maxthrssiz` is fetched (subr_param.c:230) but has **zero consumers** in
  the tree — dead knob.
* `vmm_vendor[16]` is written only from the 12-char CPUID hypervisor
  signature (initcpu.c:195,204, memcpy of 13 bytes incl. NUL) — bounded,
  hardware-trusted.
* 32-bit `limsize` overflow in init_param2 is unreachable: only pc64 and
  vkernel64 call it (both 64-bit; (size_t)physpages * PAGE_SIZE ≤ 2^43).
* `kern.hz > 1000000` → `ustick == 0` → post-boot unprivileged
  divide-by-zero via `tv.tv_usec / ustick` (kern_time.c:511 and ~8 more
  sites) — same root cause and fix locus as DF-0173 (hz validation in
  init_param1); noted here to make the fix clamp the upper bound too, not
  re-filed as a separate finding.

## Fix validation

Not performed in-guest (Low-severity boot-DoS class, no demonstrated memory
corruption; kernel rebuild cycle not warranted for a 3-line clamp).
`fix.diff` is authored against the read-only sys/ tree: validate hz/stathz
in init_param1, plus a defense-in-depth `freq <= 0` guard in
`_systimer_init_periodic`.
