sandbox: an S1 executor — a native program confined by the operating system, earning the rung by probe #281
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/sandbox-exec-os"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What was missing
The isolation ladder had no executor between a bare child process (S0) and a managed runtime (S2). As a result, sandbox-build's command steps ran either unconfined or in a microVM, with nothing in between.
What this adds
sandbox-exec-osruns a native program under the operating system's sandbox. The policy is derived from the unit's grants and denies by default:Why S1, and no higher. S1's guarantee (
spec/tiers.md) is that no resource is reachable without a capability, and that holds for every resource grants govern. A native process keeps a residue, which the crate documents:/dev/null;The clock and randomness cannot be withheld from a native process, so a grant that withholds either one is refused, never run with a capability it denies. Also refused:
S2 itself needs fuel metering and memory caps, which a native process cannot have.
The rung is earned on each host. A probe, run once per process, runs a program under a policy that grants nothing. The control run must succeed, and the program must be denied:
Only when all of that holds is the tier S1, sealed with the SPEC §7.9 mechanism:
seatbelt/<macOS version>plus a commitment to the exact policy applied. Anywhere else, the program runs unconfined at S0 with no mechanism.Linux is S0 for now. A namespace sandbox there would also need a system-call filter to enforce "no subprocess", and the fleet's Linux hosts refuse the network namespace (bubblewrap fails to set up loopback under the AppArmor user-namespace restriction), so it could not be verified.
Energy is the child's share of the host's CPU reading (
sandbox_meter::run_attributed). It isModelBasedwhere that reading comes from hardware, andEstimatorotherwise.sandbox-build: a command step runs confined, and seals S1 with its mechanism, when the confinement holds here and can enforce the step's grants. Every other step falls back to the existing unconfined child process. Today's steps withhold the clock, so they are unchanged.
CI: the macOS energy job gains a step that sets
SANDBOX_EXEC_OS_EXPECT_S1=1. With that set, the tests fail if the probe does not hold, and the step requires the confinement line and a denied read in the output. Every other runner takes the S0 branch, which the same tests also assert.check-tests-in-ci.pypasses.Checked
On the build host, macOS 27.0.1:
seatbelt/27.0.1probes S1.Host::run_and_sealseals S1 with the mechanism.Each of these mutations fails a test:
SANDBOX_EXEC_OS_EXPECT_S1makes that a failure.🤖 Generated with Claude Code