fix: tolerate benign VMM thread churn in confinement re-verification - #9017
Conversation
The NVX and Cloud Hypervisor confinement verifiers required the /proc/<pid>/task thread set to be byte-identical before and after the async cgroup/namespace checks. VMMs legitimately create and retire worker threads during initialisation, so launch failed nondeterministically with 'process identity or thread-set race'. Process replacement (start time or executable change) still fails closed. Thread churn is now handled securely: exited threads are dropped, and new or recycled TIDs are fully re-verified (Tgid, identity, groups, capabilities, no_new_privs, seccomp) before being accepted. The thread bound applies to the final sample, and a vanished main thread still fails. Error messages now name the broken invariant with observed values. Fixes #9012 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Both verifiers can accept a final task listing that omits the main thread while retaining workers.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Updates NVX and Cloud Hypervisor confinement verification to tolerate benign thread churn while preserving identity and policy checks.
Changes:
- Re-verifies new or recycled threads and tolerates vanished workers.
- Improves invariant-specific errors and final thread-count evidence.
- Adds thread-churn and fail-closed tests.
| File | Description |
|---|---|
src/nvx/confinement.ts |
Adds churn-aware NVX verification. |
src/nvx/confinement.test.ts |
Tests NVX churn scenarios. |
src/cloud-hypervisor/confinement-verifier.ts |
Adds churn-aware Cloud Hypervisor verification. |
src/cloud-hypervisor/confinement-verifier.test.ts |
Tests Cloud Hypervisor churn scenarios. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Add error handling for missing main thread in NVX confinement. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Add error handling for missing main thread in confinement verification. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 92.65% | 92.66% | ➡️ +0.01% |
| Statements | 91.13% | 91.13% | ➡️ +0.00% |
| Functions | 89.11% | 89.17% | 📈 +0.06% |
| Branches | 84.26% | 84.23% | 📉 -0.03% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/nvx/one-shot-adapter.ts |
83.5% → 82.9% (-0.60%) | 80.3% → 79.8% (-0.56%) |
src/nvx/confinement.ts |
88.2% → 88.9% (+0.73%) | 83.3% → 84.6% (+1.24%) |
src/cloud-hypervisor/confinement-verifier.ts |
82.9% → 85.1% (+2.24%) | 81.6% → 83.3% (+1.76%) |
src/log-directory-setup.ts |
96.2% → 100.0% (+3.78%) | 96.3% → 100.0% (+3.71%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
|
✅ Copilot review passed with no inline comments. @lpcox Add the |
|
Hardware validation on real KVM ( |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 92.64% | 92.65% | 📈 +0.01% |
| Statements | 91.12% | 91.13% | ➡️ +0.01% |
| Functions | 89.11% | 89.17% | 📈 +0.06% |
| Branches | 84.24% | 84.22% | 📉 -0.02% |
📁 Per-file Coverage Changes (3 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/nvx/confinement.ts |
88.2% → 88.9% (+0.73%) | 83.3% → 84.6% (+1.24%) |
src/cloud-hypervisor/confinement-verifier.ts |
82.9% → 84.7% (+1.83%) | 81.6% → 83.0% (+1.39%) |
src/log-directory-setup.ts |
96.2% → 100.0% (+3.78%) | 96.3% → 100.0% (+3.71%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts

Fixes #9012
Problem
verifyNvxConfinement, and the identical pattern inverifyCloudHypervisorConfinement, snapshotted/proc/<pid>/taskand then required it to be byte-identical after the async cgroup and namespace checks. OpenVMM creates and retires worker threads while it initialises, so launches failed nondeterministically withprocess identity or thread-set race: one pass and two failures on identical config (see #9012). This also blocks hardware validation of #9014.Fix
The security property is unchanged: the process that was verified is the process being confined.
readdirand the read (ENOENT/ESRCH), are dropped./proc/<pid>/taskonly lists members of this thread group, and the Tgid check confirms that.threadCount/observedThreadCountin the evidence now report the final verified live-thread count.Validation
jest src/nvx src/cloud-hypervisor: 669 passed.tscis clean, with no new eslint errors.smoke-nvx-copilotfollows in PR comments.