## Summary - preserve Linux bubblewrap semantics for `write -> none -> write` filesystem policies by recreating masked mount targets before rebinding narrower writable descendants - add a Linux runtime regression for `/repo = write`, `/repo/a = none`, `/repo/a/b = write` so the nested writable child is exercised under bubblewrap - document the supported legacy Landlock fallback and the split-policy bubblewrap behavior for overlapping carveouts ## Example Given a split filesystem policy like: ```toml "/repo" = "write" "/repo/a" = "none" "/repo/a/b" = "write" ``` this PR keeps `/repo` writable, masks `/repo/a`, and still reopens `/repo/a/b` as writable again under bubblewrap. ## Testing - `just fmt` - `cargo test -p codex-linux-sandbox` - `cargo clippy -p codex-linux-sandbox --tests -- -D warnings`
3.2 KiB
3.2 KiB
codex-linux-sandbox
This crate is responsible for producing:
- a
codex-linux-sandboxstandalone executable for Linux that is bundled with the Node.js version of the Codex CLI - a lib crate that exposes the business logic of the executable as
run_main()so that- the
codex-execCLI can check if its arg0 iscodex-linux-sandboxand, if so, execute as if it werecodex-linux-sandbox - this should also be true of the
codexmultitool CLI
- the
On Linux, the bubblewrap pipeline uses the vendored bubblewrap path compiled into this binary.
Current Behavior
- Legacy
SandboxPolicy/sandbox_modeconfigs remain supported. - Bubblewrap is the default filesystem sandbox pipeline and is standardized on the vendored path.
- Legacy Landlock + mount protections remain available as an explicit legacy fallback path.
- Set
features.use_legacy_landlock = true(or CLI-c use_legacy_landlock=true) to force the legacy Landlock fallback. - The legacy Landlock fallback is used only when the split filesystem policy is
sandbox-equivalent to the legacy model after
cwdresolution. - Split-only filesystem policies that do not round-trip through the legacy
SandboxPolicymodel stay on bubblewrap so nested read-only or denied carveouts are preserved. - When the default bubblewrap pipeline is active, the helper applies
PR_SET_NO_NEW_PRIVSand a seccomp network filter in-process. - When the default bubblewrap pipeline is active, the filesystem is read-only by default via
--ro-bind / /. - When the default bubblewrap pipeline is active, writable roots are layered with
--bind <root> <root>. - When the default bubblewrap pipeline is active, protected subpaths under writable roots (for
example
.git, resolvedgitdir:, and.codex) are re-applied as read-only via--ro-bind. - When the default bubblewrap pipeline is active, overlapping split-policy
entries are applied in path-specificity order so narrower writable children
can reopen broader read-only or denied parents while narrower denied subpaths
still win. For example,
/repo = write,/repo/a = none,/repo/a/b = writekeeps/repowritable, denies/repo/a, and reopens/repo/a/bas writable again. - When the default bubblewrap pipeline is active, symlink-in-path and non-existent protected paths inside
writable roots are blocked by mounting
/dev/nullon the symlink or first missing component. - When the default bubblewrap pipeline is active, the helper explicitly isolates the user namespace via
--unshare-userand the PID namespace via--unshare-pid. - When the default bubblewrap pipeline is active and network is restricted without proxy routing, the helper also
isolates the network namespace via
--unshare-net. - In managed proxy mode, the helper uses
--unshare-netplus an internal TCP->UDS->TCP routing bridge so tool traffic reaches only configured proxy endpoints. - In managed proxy mode, after the bridge is live, seccomp blocks new AF_UNIX/socketpair creation for the user command.
- When the default bubblewrap pipeline is active, it mounts a fresh
/procvia--proc /procby default, but you can skip this in restrictive container environments with--no-proc.
Notes
- The CLI surface still uses legacy names like
codex debug landlock.