Skip to content

feat(sandbox): pluggable handler for bootstrap-subsystem failures#1549

Open
dims wants to merge 1 commit into
NVIDIA:mainfrom
dims:feat/sandbox-failure-handler
Open

feat(sandbox): pluggable handler for bootstrap-subsystem failures#1549
dims wants to merge 1 commit into
NVIDIA:mainfrom
dims:feat/sandbox-failure-handler

Conversation

@dims
Copy link
Copy Markdown
Contributor

@dims dims commented May 23, 2026

The supervisor performs three optional hardening steps that the host kernel may refuse: unshare(CLONE_NEWNET), the supervisor seccomp prelude, and the workload seccomp filter. On bare-metal Linux a refusal is fatal — the supervisor cannot meet its hardening contract and aborts. Under an outer sandbox (gVisor, Firecracker, Kata) the host runtime is itself the enforcing boundary and routinely intercepts those syscalls, leaving the supervisor unable to boot.

This change introduces a pluggable SandboxFailureHandler trait. The default StrictHandler preserves the historical contract — every refusal aborts. Outer-sandbox integrations link this crate and call set_failure_handler once at process start to register a handler that returns Ok(()) for the kinds the host runtime is expected to manage. The three internal call sites in run_sandbox and sandbox::linux::enforce route through failure_handler().handle(kind, err)?.

The change also makes drop_privileges idempotent: when euid/egid already match the resolved target, skip initgroups(3), which would otherwise fail without CAP_SETGID.

The stock openshell-sandbox binary never calls set_failure_handler, so its behaviour against this commit is byte-identical to upstream main. All 777 sandbox library tests pass unchanged.

Files touched (3 files, +71 / −7):

  • crates/openshell-sandbox/src/lib.rs — the SandboxFailureKind enum, the SandboxFailureHandler trait, StrictHandler, the set-once handler slot, set_failure_handler, and the netns-create + supervisor-seccomp call sites.
  • crates/openshell-sandbox/src/sandbox/linux/mod.rs — workload-seccomp call site.
  • crates/openshell-sandbox/src/process.rs — idempotent drop_privileges fast-path.

Verification:

  • cargo fmt --all -- --check clean on the touched files.
  • cargo test -p openshell-sandbox --lib — 777 tests pass.
  • cargo clippy -p openshell-sandbox --lib --tests -- -D warnings — zero new warnings introduced (pre-existing warnings on main unchanged).
  • mise run pre-commit — to be re-verified by CI after copy-pr-bot mirrors.

Motivation: the substrate-based POC at dims/openshell-driver-substrate needs the supervisor to boot inside a gVisor actor; the host runtime refuses the three syscalls above. Without a trait-shaped extension point the integration would have to fork the supervisor. This is the smaller, upstream-friendly alternative to the earlier env-variable-gated #1548 — same end result, but expressed as a typed Rust API and capable of selective per-kind policy.

Checklist:

  • Follows Conventional Commitsfeat(sandbox): …
  • Commits are signed off (DCO).
  • Architecture docs updated — not applicable; the new behaviour is opt-in via a public Rust API only, no existing user-visible contract changes.

@dims dims requested review from a team, derekwaynecarr, maxamillion and mrunalp as code owners May 23, 2026 22:52
dims added a commit to dims/openshell-driver-substrate that referenced this pull request May 23, 2026
Two upstream PRs are now open against NVIDIA/OpenShell with the same
end result but different shapes — #1548 (env-var gate) and #1549
(SandboxFailureHandler trait + setter). Update the README "Companion
changes upstream" table and the poc-intro §1 header, §3 components
table, §6.1 detail, and §9 "Where to next" item to present both
alternatives side by side.

Signed-off-by: Davanum Srinivas <dsrinivas@nvidia.com>
@dims
Copy link
Copy Markdown
Contributor Author

dims commented May 26, 2026

cc @drew @mrunalp @derekwaynecarr

The supervisor performs three optional hardening steps that the host
kernel may refuse: unshare(CLONE_NEWNET), the supervisor seccomp
prelude, and the workload seccomp filter. On bare-metal Linux a refusal
is fatal. Under an outer sandbox (gVisor, Firecracker, Kata) the host
runtime is itself the enforcing boundary and routinely intercepts those
syscalls, leaving the supervisor unable to boot.

Introduce a pluggable SandboxFailureHandler trait. The default
StrictHandler preserves the historical contract — every refusal aborts.
Outer-sandbox integrations link this crate and call set_failure_handler
once at process start to register a handler that returns Ok(()) for the
kinds the host runtime is expected to manage. The three internal call
sites in run_sandbox and sandbox::linux::enforce route through
failure_handler().handle(kind, err)?.

Also make drop_privileges idempotent: when euid/egid already match the
resolved target, skip initgroups(3), which would otherwise fail without
CAP_SETGID.

The stock openshell-sandbox binary never calls set_failure_handler, so
its behaviour against this commit is byte-identical to upstream main.
All 777 sandbox library tests pass unchanged.

Signed-off-by: Davanum Srinivas <dsrinivas@nvidia.com>
@dims dims force-pushed the feat/sandbox-failure-handler branch from fafa9a4 to e295996 Compare May 27, 2026 01:22
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 27, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@drew drew added the test:e2e Requires end-to-end coverage label May 27, 2026
@github-actions
Copy link
Copy Markdown

Label test:e2e applied, but pull-request/1549 is at fafa9a4 while the PR head is e295996. A maintainer needs to comment /ok to test e2959961616b5ed22d74c73c7c9707b91693453c to refresh the mirror. Once the mirror catches up, re-run Branch E2E Checks from the Actions tab.

@drew
Copy link
Copy Markdown
Collaborator

drew commented May 27, 2026

/ok to test e295996

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

Labels

test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants