fix(sandbox): spawn confined argv directly (round 1)

This commit is contained in:
Hypatia May
2026-08-04 12:04:48 +08:00
parent 2eedb54849
commit e36d040d0a
34 changed files with 392 additions and 282 deletions
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/core-data-structures/sandbox.md
sandbox.md: 8483104e0aab78779acb52b232a205280c93cd2b
sandbox.zh.md: b283095f1c847a4b2fca5a109e7894d6e3479839
sandbox.md: 63a80084c5b6b25d55495d2d96daef73380993f6
sandbox.zh.md: 447552e5c80b9cf3f4dd0b684c0607843a064448
+2 -2
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 entry for its own pre-exec refusal dialect. The provider maps those entries into one rule and adds a separate argv0-scoped rule for outer-shell missing or unexecutable failures. This makes an executable custom runner rejecting its profile distinguishable from the wrapped command exiting with the same status.
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.
## 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 selected runner can also fail closed at execution time, in which case a matching structured rule carries the same infrastructure meaning. 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. 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.
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.
+2 -2
View File
@@ -139,10 +139,10 @@ interface ConfinedArgv {
}
```
面向运维人员的本地提供方配置键仍为 `runnerFailureSignatures`:运维人员配置的 runner 必须为自身的 pre-exec 拒绝方言提供至少一条条目。提供方会将这些条目映射到一条规则,并另加一条按 argv0 限定的外层 shell 规则,用于识别命令缺失或不可执行。这使得可执行的自定义 runner 拒绝其 profile 的情况能够与被包装命令以相同状态码退出的情况区分开来
面向运维人员的本地提供方配置键仍为 `runnerFailureSignatures`:运维人员配置的 runner 必须为自身的 pre-exec 拒绝方言提供至少一个非空、单行、不区分大小写的子串。提供方会将这些条目映射到一条规则。消费方直接 spawn `ConfinedArgv.argv`,因此 runner 缺失或不可执行时会在 spawn 通道遭拒,而不是由 stderr 规则判定;进程启动后,126 或 127 等子进程退出码仍按普通结果处理,除非匹配所选 runner 文档所定义的致命签名
## 提供方与 fail-closed 错误
`ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。已选定的 runner 也可能在执行时 fail-closed,此时匹配到的结构化规则承载相同的基础设施含义。对于受限策略,静默的无隔离透传永远不合法。
`ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。直接 spawn 所返回的 argv 时若遭拒,即可证明受限启动从未开始;该拒绝具有相同的基础设施含义,并以原始错误作为详细信息。进程启动后,匹配到的结构化规则标识 runner 拒绝。对于受限策略,静默的无隔离透传永远不合法。
提供方探测在多个候选后端之间仲裁,结果在提供方生命周期内缓存。只有一个候选后端的平台可以直接选定它;执行时拒绝仍保留安全属性。本地提供方将 bwrap 和 Seatbelt 报告为 full,并保留 Landlock 启动器的 full/partial 内核裁定。