Skip to content

fix: tolerate benign VMM thread churn in confinement re-verification - #9017

Merged
lpcox merged 3 commits into
mainfrom
fix-nvx-confinement-thread-race
Sep 25, 2026
Merged

lpcox merged 3 commits into
mainfrom
fix-nvx-confinement-thread-race

Conversation

@lpcox

@lpcox lpcox commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Fixes #9012

Problem

verifyNvxConfinement, and the identical pattern in verifyCloudHypervisorConfinement, snapshotted /proc/<pid>/task and 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 with process 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.

  • Still fails closed: a changed process start time, a changed executable (for NVX, both path and dev/inode), a main thread that vanishes, a new thread that violates policy, or a final thread set over the 256-thread bound.
  • Now accepted safely:
    • Worker threads that exit between samples, or between readdir and the read (ENOENT/ESRCH), are dropped.
    • New threads and recycled TIDs (start time changed) are fully re-verified before being accepted: Tgid, uid/gid, groups, capabilities, no_new_privs, and seccomp. /proc/<pid>/task only lists members of this thread group, and the Tgid check confirms that.
  • The identity re-check now runs after thread re-verification, so it brackets all the evidence.
  • Errors now name the broken invariant and show the observed and expected values.
  • threadCount / observedThreadCount in the evidence now report the final verified live-thread count.

Validation

  • Added churn tests for both verifiers covering new, exited, vanished-mid-read, and recycled threads, a policy-violating new thread, executable replacement, main-thread loss, and the final-sample bound.
  • Mutation check: running the new tests against the old verifiers gives 14 failures; with the fix, 31/31 pass.
  • jest src/nvx src/cloud-hypervisor: 669 passed. tsc is clean, with no new eslint errors.
  • Hardware validation via smoke-nvx-copilot follows in PR comments.

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>
Copilot AI balanced review requested due to automatic review settings September 25, 2026 21:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 High severity

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.

Comment thread src/cloud-hypervisor/confinement-verifier.ts
Comment thread src/nvx/confinement.ts
lpcox and others added 2 commits September 25, 2026 14:35
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>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Copilot review passed with no inline comments.

@lpcox Add the ready-for-aw label to this PR to trigger agentic CI smoke tests.

@lpcox

lpcox commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

Hardware validation on real KVM (smoke-nvx-copilot on this branch): 3/3 runs passed all 4 checks (microvm-run, guest-assertions, workspace-copy-back, copilot-inference), with no identity/thread-set race errors. Before this fix, 2 of 3 runs on identical config failed at this verifier.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NVX/Cloud Hypervisor confinement verifier fails intermittently on a thread-set TOCTOU race

2 participants