fix(sandbox): round 5 harden spawn attribution

This commit is contained in:
Hypatia May
2026-08-04 16:06:54 +08:00
parent ec4a070f0e
commit 293fac9421
14 changed files with 192 additions and 87 deletions

View File

@@ -139,10 +139,10 @@ interface ConfinedArgv {
}
```
The operator-facing local-provider key remains `runnerFailureSignatures`: an operator-configured runner must supply at least one non-empty, single-line, case-insensitive substring for its own pre-exec refusal dialect. The provider maps those entries into one rule. Consumers directly spawn `ConfinedArgv.argv`, so a missing or unexecutable runner rejects through the spawn channel rather than a stderr rule; after a process starts, child exits such as 126 or 127 remain ordinary unless the selected runner's documented fatal signature matches.
The operator-facing local-provider key remains `runnerFailureSignatures`: an operator-configured runner must supply at least one non-empty, single-line, case-insensitive substring for its own pre-exec refusal dialect. The provider maps those entries into one rule. Consumers directly spawn `ConfinedArgv.argv`, so a missing, non-executable, or unloadable runner — including a script whose shebang interpreter is unavailable — rejects through the spawn channel rather than a stderr rule; after a process starts, child exits such as 126 or 127 remain ordinary unless the selected runner's documented fatal signature matches.
## Provider and fail-closed errors
`ctx.sandbox.confine(argv, policy)` returns a `ConfinedArgv` or throws `SandboxUnavailableError` with code `SANDBOX_UNAVAILABLE` when no usable backend exists. A direct spawn rejection of the returned argv proves the confined launch never started and carries the same infrastructure meaning with the original error as detail. After a process starts, a matching structured rule identifies a runner refusal. Silent unconfined passthrough is never legal for a confined policy.
`ctx.sandbox.confine(argv, policy)` returns a `ConfinedArgv` or throws `SandboxUnavailableError` with code `SANDBOX_UNAVAILABLE` when no usable backend exists. Any direct spawn rejection of the returned argv proves the confined launch never started, but only an executable-class error with Node spawn provenance for provider argv[0] after the caller-owned workdir is independently verified usable carries infrastructure meaning and the original error as detail. Invalid or unusable workdirs, resource failures, unrelated syscalls, and unstructured rejections retain the consumer's ordinary command-start semantics. After a process starts, a matching structured rule identifies a runner refusal. Silent unconfined passthrough is never legal for a confined policy.
Provider probing arbitrates between multiple candidates and is cached for the provider lifetime. A platform with one candidate may select it directly; execution-time refusal retains the safety property. The local provider reports bwrap and Seatbelt as full and preserves the Landlock launcher's full/partial kernel verdict.