β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5661

vkernel's only host-SIGTERM shutdown path is a silent no-op whenever pid 1 does not catch SIGUSR2: 'Shutting down...' is printed and nothing stops

Summary

shutdown_intr unconditionally ksignal(initproc, SIGUSR2) but the delivery layer silently discards default-action signals to pid 1, and execsigs only resets caught signals - until init(8) has armed its SIGUSR2 handler the signal is posted and dropped. Live-proven: kill -TERM mid-boot or post-boot prints 'Shutting down...' and the vkernel stays alive indefinitely (commands still execute inside the 'shut-down' guest; in-guest kill -USR2 1 leaves pid 1 alive); a SIGTERM burst during boot yields hundreds of Shutting-down lines while boot continues. The documented stop mechanism silently fails against any booting vkernel or non-init init_path - the host then powers off underneath the still-running vkernel (dirty images, stale pidfiles). SIG_CATCH-gate + shutdown_nice fallback fix validated (same 3-hunk diff as DF-5660): clean halt through boot() to cpu halt.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5661 Β· 11 files
FileTypeDescriptionSize
run.sh β€” 127 B view raw
vkinit3.c β€” 164 B view raw
build_image.sh β€” 1.0 KB view raw
run.midboot.noop.log β€” 1.9 KB view raw
wedge_probe.log β€” 2.1 KB view raw
run.fixboot.log β€” 2.2 KB view raw
bootlog_excerpt.txt β€” 3.5 KB view raw
env.txt β€” 220 B view raw
fix.diff β€” 2.8 KB view raw
VERDICT.md β€” 3.8 KB ↓ raw
verdict.json β€” 3.8 KB view raw
VERDICT.md
↓ download raw

DF-5661 β€” VERDICT

Status: reproduced (impact: dos β€” the vkernel's shutdown mechanism silently fails; SIGTERM cannot stop a booting vkernel or any vkernel whose pid 1 is not real init(8); host shutdown leaves the vkernel running and it is killed uncleanly underneath, with dirty guest disk images).

Mechanism (certain)

  1. Host SIGTERM β†’ vkernel shutdownsig (shutdown.c:77) β†’ signalintr(2) (machintr.c:169) β†’ INT2 ithread β†’ shutdown_intr (shutdown.c:91): kprintf("Caught SIGTERM ... Shutting down...\n") then ksignal(initproc, SIGUSR2) (shutdown.c:95) β€” init(8)'s poweroff trigger (sbin/init/init.c:1343).
  2. If pid 1 has not armed a SIGUSR2 handler yet β€” the entire boot window (create_init at SI_SUB_CREATE_INIT runs long before start_init execs, and handlers are only installed after exec) β€” or ever (non-init(8) pid 1): kern_sig's issignal loop hits case SIG_DFL: β†’ if (p->p_pid <= 1) break; /* == ignore */ (kern_sig.c:2134-2144). The signal is posted and silently discarded.
  3. execsigs() (kern_sig.c:426-445) resets only caught signals, so a SIGUSR2 posted while start_init is still building/exec'ing the first image cannot be rescued by exec either.

Live proof (rig: VKERNEL64 on the DragonFly guest, /vkroot.img,

init_path=/bin/vkinit β†’ sh as pid 1)

  • run.midboot.noop.log + wedge_probe.log: kill -TERM mid-boot and post-boot β†’ "Caught SIGTERM from host system. Shutting down..." β†’ the vkernel stays alive indefinitely (S5, minutes observed); the operator's stop signal has no effect.
  • Guest liveness proven post-SIGTERM by console injection: echo GUEST_ALIVE_OK executed; kill -USR2 1; echo STILL_HERE… printed STILL_HERE_AFTER_USR2 β€” pid 1 ignores SIGUSR2 via the pid≀1 guard; no panic, no death, no shutdown.
  • At-scale variant: a SIGTERM burst during boot yields a stream of "Shutting down..." lines while boot proceeds normally (bootlog_excerpt.txt; hundreds of hits, zero effect).

Impact ceiling

Not memory corruption; a reliability/availability defect with data-loss adjacency: host shutdown scripts (killall TERM, rc.d vkernel stop, lockf-based pidfile scripts β€” the machinery init.c:1375-1404 exists to support) silently fail against a booting vkernel; the host then powers off under the still-running vkernel β†’ unclean guest disk state, stale locked pidfile. Trigger needs only the ability to signal the vkernel (same uid or root), i.e. exactly the documented operational path.

Fix validation (fixed)

fix.diff = gate the ksignal on ps_sigcatch (the kernel's own delivery criterion) and route the fallback through the in-kernel shutdown_nice(RB_POWEROFF|RB_HALT) path, plus the two kern_shutdown.c hardening hunks (shutdown_nice's identical blind-SIGINT bug; the curproc==NULL kern_closefrom assertion that fires when boot() runs from ithread context β€” hit live during validation and fixed).

Patched kernel, handler-less pid 1 (vkinit3, standing in for pre-arm init(8)), same kill -TERM: run.fixboot.log shows the complete clean kernel-side halt (boot() called on cpu#0 … The operating system has halted. … cpu halt, exiting vkernel, monitor exit, FIXB RESULT: exited) β€” the no-op is gone, the vkernel stops cleanly, the guest host is untouched.

Why not uid0

No memory-safety primitive: a dropped signal. The deliverable is the demonstrated silent-failure of the kernel's own shutdown path and its clean repair.

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.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Baseline: kill -TERM (mid-boot and full-boot, handler-less pid 1) -> 'Caught SIGTERM ... Shutting down...' then the vkernel stays alive forever (live-guest probes). Patched: identical trigger -> complete clean halt (boot() on cpu#0, system threads stopped, 'The operating system has halted.', cpu halt, exit(EX_OK), monitor exits); FIXB RESULT: exited.

run.fixboot.log (full halt transcript); bootlog_excerpt.txt (serial console: FIXB RESULT: exited)
↓ fix.diffper-fix-DF-5661

Confirmed kernel references

Detail

Exploit chain

same-uid signal (operator stop script / host shutdown sweep) during vkernel boot -> shutdown_intr prints 'Shutting down...' -> ksignal(initproc, SIGUSR2) dropped by the pid<=1 SIG_DFL guard -> vkernel never stops -> host powers off underneath the running vkernel -> unclean guest disk images, stale locked pidfile

Evidence (decisive lines)

run.midboot.noop.log + wedge_probe.log (message then live guest: GUEST_ALIVE_OK, STILL_HERE_AFTER_USR2); bootlog_excerpt.txt (no-op at scale); run.fixboot.log (clean kernel-side halt on the patched kernel); VERDICT.md

PoC changes

run.sh adapted from the DF-5607 rig driver; added vkinit3 (pid-1 with no handlers) to /vkroot.img for fix validation; probes injected through the fifo console to prove guest liveness post-SIGTERM.

Verified recommended fix

Only ksignal init when init actually catches SIGUSR2 (ps_sigcatch gate) and otherwise take the in-kernel shutdown path (shutdown_nice(RB_POWEROFF|RB_HALT) with the kern_shutdown.c hardening hunks); see fix.diff.

Verdict

The vkernel's only host-SIGTERM shutdown path, shutdown_intr's ksignal(initproc, SIGUSR2) (shutdown.c:95), is a silent no-op whenever pid 1 does not catch SIGUSR2: kern_sig's issignal loop drops default-action signals to pid<=1 (kern_sig.c:2134-2144) and execsigs() only resets caught signals, so the whole boot window (create_init .. init(8) arming handlers) -- and permanently for a vkernel whose init_path is not real init(8) -- swallows the documented stop signal after printing 'Shutting down...'. Rig-proven live: kill -TERM mid-boot and post-boot left the vkernel alive indefinitely (verified by executing console commands inside the 'shut-down' guest: GUEST_ALIVE_OK; and kill -USR2 1 from inside the guest: STILL_HERE_AFTER_USR2); a burst of SIGTERMs during boot produced a stream of 'Shutting down...' lines while boot continued normally. With fix.diff (shared with DF-5660) and a handler-less pid 1 standing in for pre-arm init(8), the same kill -TERM now takes the in-kernel path and halts cleanly: 'boot() called on cpu#0 ... The operating system has halted. ... cpu halt, exiting vkernel', monitor exits, guest host untouched.