cothread_wakeup()'s SIGINT vector forces a process-wide empty-handler latch that permanently disables the vkernel console's ^C handling
Summary
The wakeup vector is SIGINT - a signal with existing process-wide meaning (vconsinit installs vconssignal for it early in boot), and making it survivable requires vktimer_thread to install an empty SA_NODEFER handler process-wide from the cothread, stomping the console handler forever. Traced live on a real boot (install sequence with nm-confirmed addresses) and behaviorally confirmed: 3x kill -INT post-boot leaves the vkernel alive, SIGTERM control still works. Operators lose the vconssignal terminal-restore path; any future SIGINT consumer breaks identically. Move-the-vector fix (dedicated blocked signal, or chain to the saved disposition).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5608 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| sigtrace.c | β | 1.4 KB | view raw | |
| run.sh | β | 100 B | view raw | |
| run.log | β | 2.2 KB | view raw | |
| run.driver.log | β | 996 B | view raw | |
| verdict.json | β | 2.7 KB | view raw | |
| VERDICT.md | β | 2.8 KB | β raw |
DF-5608 β VERDICT
Status: reproduced (runtime, one traced boot + one confirmation boot). Impact: none (functional/operational regression β no memory safety, no DoS; SIGTERM/SIGKILL still work). Confidence: certain.
What was proven
On a real VKERNEL64 boot with an LD_PRELOAD sigaction() tracer:
- The console subsystem installs
vconssignalfor SIGINT early (console.c:344-360; traced installhandler=0x72b6d0 flags=0,nm:vconssignal). - At
initclocksthe vktimer cothread β a different pthread β installs the emptySA_NODEFERlatch (handler=0x72aa00 flags=0x10,nm:vktimer_sigint; systimer.c:223-227), which being a process-widesigaction()replacesvconssignal. This replacement is REQUIRED bycothread_wakeup()'s choice of SIGINT as the thread-directed wakeup vector (cothread.c:196): SIGINT is not incpu_mask_all_signals()'s set (machintr.c:205), so without hijacking the disposition the wakeup SIGINT would run whatever handler the process had β in the cothread, with %gs=0 (see DF-5607 for what a faulting handler does there). - Behavioral consequence, live: three
kill -INTs to the booted vkernel child leave it ALIVE β host ^C is dead post-boot (vconssignalnever runs: no terminal restore, no clean re-raise). Control: SIGTERM still reaches the console handler path ("Caught SIGTERM from host system. Shutting down...").
Root cause is shared between cothread.c (the SIGINT vector choice at cothread.c:196 β a signal the process ALSO uses for console control) and systimer.c (the process-wide latch at :227). The console's ^C feature is silently lost after boot; the operator must use SIGTERM (wrapper forwards it, init.c:216-219) or SIGKILL.
Fix direction
The wakeup vector should not be a signal with existing process-wide
meaning. Options: use a dedicated unused signal (e.g. one of the
realtime signals) for cothread_wakeup() β blocking it in every
cothread via cpu_mask_all_signals() (machintr.c) β or save/restore
the previous SIGINT disposition and chain to vconssignal from
vktimer_sigint when the signal is process-directed rather than
thread-directed. No fix.diff authored (Low severity, no memory-safety
impact; behavioral evidence only).
Environment
Same rig as DF-5607 (guest DragonFly 6.5-DEVELOPMENT, VKERNEL64
in-guest build, /vkroot.img, -n 2).
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.
(No fix.diff for this item: documented recommendation only - see Fix above.)
Fix verification
not_testableNo fix build for a Low/operational finding (contract skips Low hardening); behavioral fix direction documented in VERDICT.md.
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-5608/run.driver.log (SIGTRACE install sequence with nm-confirmed symbol addresses 0x72b6d0=vconssignal / 0x72aa00=vktimer_sigint; AFTER_SIGINT_3 STILL ALIVE; SIGTERM shutdown in console tail); run.log (full traced console)
PoC changes
Authored from scratch (no seed): LD_PRELOAD sigaction tracer + child-vs-wrapper targeting (the init.c fork wrapper SIG_IGNs SIGINT itself, so the behavioral test must target the vkernel child pid).
Verified recommended fix
Move the cothread wakeup vector off SIGINT (dedicated signal, blocked in cothreads via cpu_mask_all_signals) or chain to the previous disposition from vktimer_sigint.
Verdict
cothread_wakeup() pthread_kills SIGINT into cothreads (cothread.c:196); to make that survivable the vktimer cothread installs an empty SA_NODEFER SIGINT handler process-wide (systimer.c:223-227), which permanently REPLACES the vkernel console's SIGINT handler vconssignal (console.c:355, installed earlier at console init). Traced live on a real VKERNEL64 boot: install sequence SIG_IGN(init.c:209) -> vconssignal(console.c:355) -> vktimer_sigint(systimer.c:227, from the cothread pthread, flags=SA_NODEFER); after boot, 3x kill -INT to the vkernel child leaves it alive (host ^C dead -- no terminal restore, no clean termination), while SIGTERM still shuts it down. Operational regression owned by the SIGINT vector choice; no memory-safety impact.
No comments yet.