# DF-5568 — VERDICT

**Status: reproduced (dead code proven at scale, A/B against the one-cast fix).**
**Impact: none (correctness / redundant-signal-churn defect; no memory safety,
no privilege, no leak, no hang). Severity: Low. Confidence: certain.**

## Root cause (static)

`sys/platform/vkernel64/platform/systimer.c:301-303`:

```c
if (vktimer_cotd && (ssysclock_t)(reload - vktimer_target) < 0) {
	while ((sysclock_t)(reload - vktimer_target) < 0)
		reload = atomic_swap_long(&vktimer_target, reload);
	cothread_wakeup(vktimer_cotd, &vktimer_ts);
}
```

`sysclock_t` = `__uint64_t` (`sys/sys/systimer.h:51`); `ssysclock_t` =
`int64_t` (`sys/sys/systimer.h:52`). `(sysclock_t)(x) < 0` is always
false for an unsigned type, so the `while` body — the
`atomic_swap_long()` that lowers `vktimer_target` to the earliest
deadline any vcpu has programmed — is dead code. The `if` on the line
above evaluates the *identical expression* with the correct
`(ssysclock_t)` cast; the `while`'s cast is a typo.

## What the dead protocol was for

`vktimer_target` is the cothread's next-wake deadline
(`vktimer_thread()`, `systimer.c:262-263`). When a vcpu programs a
one-shot systimer earlier than that deadline, `vktimer_intr_reload()`
wants to (a) atomically pull the target down and (b) kick the cothread
(`cothread_wakeup()` → zeroes `vktimer_ts` + `pthread_kill(SIGINT)`,
`cothread.c:192-197`). With the loop dead, only (b) happens, and (b) is
re-fired for *every* earlier-than-stale-target reload rather than only
those that lower the target — redundant `pthread_kill(SIGINT)` churn
under dense one-shot timer load (the vkernel "signal storm" surface),
plus the loss of the intended race-window narrowing between
`vktimer_reload[]` stores (`systimer.c:300`) and the cothread's rescan
(`systimer.c:254-274`).

## Verification (DragonFly guest, vkernel64 rig after DF-5337/DF-5538/DF-5556)

Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
(X86_64_GENERIC, hw.ncpu=6), cc 8.3 [DragonFly].

Built two vkernel64 kernels from the guest's /usr/src
(`make -j6 nativekernel KERNCONF=VKERNEL64`, DF-5474 link workaround:

- `kernel.instr`: stock logic + counters `debug.vkt_if` / `debug.vkt_swap`
  (`instr.diff`);
- `kernel.fixed`: + the one-cast fix (`instrfix.diff`; clean fix in `fix.diff`).

Booted each with `-m 512m -r /vkroot2.img -n 2 -e init_path=/bin/vkinit`;
inside: T0 counters → `drift` → two 20 s `hog`s (2 ms `clock_nanosleep`
loops) → T1 counters.

### Results (`run.instr.log`, `run.fixed.log`)

| build | vkt_if T0→T1 | vkt_swap T0→T1 |
|---|---|---|
| stock  `(sysclock_t)` | 16042 → 42294 | **0 → 0** |
| fixed `(ssysclock_t)` | 12411 → 32540 | **12515 → 32722** |

- Stock: the `if` body ran 42,294 times; the `while` body ran **0** times.
  Dead code proven at scale (idle boot alone produced 16,042 `if` entries).
- Fixed: the `while` body runs ~1:1 with the `if` (slightly more —
  multiple iterations under contention), i.e. the intended atomic
  target-lowering protocol is restored by the single cast change.
- No functional regression: `DRIFT10MS ratio 1.000` on both builds,
  hogs complete (`HOGS_RC=0`), vkernel `ALIVE_AT_END` on both builds,
  no panic, no watchdog.
- `DRIFT1MS ratio 10.000` (identical both builds) is the *documented*
  coarse-timer clamp `systimer.c:275-282` with `use_precise_timer = 0`
  (default, `init.c:126`; `-t` enables precise mode) — pre-existing
  designed behavior, not this finding, and unaffected by the fix.

### Fix validation

- Baseline reproduces the defect (vkt_swap = 0 despite 42k opportunities):
  `fix_baseline_reproduced = true`.
- Patched kernel: defect gone (vkt_swap > 0), timer function unchanged
  (drift identical, workload completes, vkernel alive):
  `fix_patched_reproduced = true` → `fix_status = fixed`.

## Why severity is Low (negative results that bound it)

- No memory-safety surface in the file: no copyin/copyout, no dynamic
  allocation after boot, arrays indexed only by `gd_cpuid < MAXCPU`
  (`systimer.c:300`; `optcpus` clamped 1..MAXCPU at `init.c:395-397`);
  cothread reads of `vktimer_reload[]`/`vktimer_target` are aligned
  64-bit scalars (tear-free on x86_64).
- No missed-wakeup hang: the cothread recomputes `vktimer_target` from
  `vktimer_reload[]` every pass and sleeps for the min delta; even a
  stale target can only cause *extra* wakeups, not fewer
  (`systimer.c:246-283`).
- No teardown UAF: `vktimer_cotd` is never destroyed (no
  `cothread_delete()` caller for it; `rg` over vkernel64).
- Boot-order race killed: `ap_tids[]` is populated synchronously by
  `mp_start()` at `SI_BOOT2_START_CPU` (`autoconf.c:101,199`,
  `mp.c:403,464-470`) which precedes `SI_BOOT2_CLOCKREG`
  (`kernel.h:158,162`; `systimer.c:136`), so the cothread never signals
  a nonexistent thread; `pthread_kill(ap_tids[n], SIGURG)`
  (`systimer.c:258`) is safe post-boot.
- Runtime re-selection of the interrupt cputimer can't re-run
  `vktimer_intr_initclock()` (no second cothread):
  `initclock` runs only from the `SI_ORDER_SECOND` sysinit
  (`kern_cputimer.c:432-465`), and with a single registered "vkernel"
  intr timer the `kern.cputimer_intr.select` sysctl re-selects the same
  object (`kern_cputimer.c:518-521`).
- `sys_cputimer` swap is boot-time-only over static structures
  (`dummy_cputimer` → `vkernel_cputimer`, `kern_cputimer.c:84-117`),
  `count()` is stateless — no cothread-vs-swap UAF.
- Reload arithmetic is clamped (`systimer.c:295-299`: negative→1,
  ≥freq→freq); `muldivu64(reload ≤ freq-1, 1e9, freq)` cannot overflow
  and yields `tv_nsec < 1e9` (`systimer.c:283`).

## Rig notes (what had to be fixed vs the seed)

- `mkdir -p /var/vkernel` + `sysctl vm.vkernel_enable=1` required before
  first boot (fresh guest snapshot).
- The run-monitor must not grep for a marker that appears in the *echoed*
  fifo input (first run self-terminated early) — output-only marker
  `TERMINUS: 42` used instead.
- `fix.diff` is generated against the pristine file; the instrumented
  verification build needs the combined `instrfix.diff` (instrumentation
  + cast) — applying `fix.diff` on top of `instr.diff` fails on context
  (braces added around the `while` body) by construction.
- `uname` didn't land in the image (cp silently skipped); `kern.clockrate`
  used instead — cosmetic only.

## Artifacts

`instr.diff`, `instrfix.diff`, `fix.diff`, `drift.c`, `hog.c`,
`build.sh`, `run.sh`, `build.instr.log`, `build.fixed.log`,
`run.instr.log`, `run.fixed.log`, `vkcon.instr.log`, `vkcon.fixed.log`,
`env.txt`, `manifest.json`, `verdict.json`.

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