mirror of
https://github.com/openai/codex.git
synced 2026-05-01 03:42:05 +03:00
Fixes #15283. ## Summary Older system bubblewrap builds reject `--argv0`, which makes our Linux sandbox fail before the helper can re-exec. This PR keeps using system `/usr/bin/bwrap` whenever it exists and only falls back to vendored bwrap when the system binary is missing. That matters on stricter AppArmor hosts, where the distro bwrap package also provides the policy setup needed for user namespaces. For old system bwrap, we avoid `--argv0` instead of switching binaries: - pass the sandbox helper a full-path `argv0`, - keep the existing `current_exe() + --argv0` path when the selected launcher supports it, - otherwise omit `--argv0` and re-exec through the helper's own `argv[0]` path, whose basename still dispatches as `codex-linux-sandbox`. Also updates the launcher/warning tests and docs so they match the new behavior: present-but-old system bwrap uses the compatibility path, and only absent system bwrap falls back to vendored. ### Validation 1. Install Ubuntu 20.04 in a VM 2. Compile codex and run without bubblewrap installed - see a warning about falling back to the vendored bwrap 3. Install bwrap and verify version is 0.4.0 without `argv0` support 4. run codex and use apply_patch tool without errors <img width="802" height="631" alt="Screenshot 2026-03-25 at 11 48 36 PM" src="https://github.com/user-attachments/assets/77248a29-aa38-4d7c-9833-496ec6a458b8" /> <img width="807" height="634" alt="Screenshot 2026-03-25 at 11 47 32 PM" src="https://github.com/user-attachments/assets/5af8b850-a466-489b-95a6-455b76b5050f" /> <img width="812" height="635" alt="Screenshot 2026-03-25 at 11 45 45 PM" src="https://github.com/user-attachments/assets/438074f0-8435-4274-a667-332efdd5cb57" /> <img width="801" height="623" alt="Screenshot 2026-03-25 at 11 43 56 PM" src="https://github.com/user-attachments/assets/0dc8d3f5-e8cf-4218-b4b4-a4f7d9bf02e3" /> --------- Co-authored-by: Michael Bolin <mbolin@openai.com>
68 lines
4.0 KiB
Markdown
68 lines
4.0 KiB
Markdown
# codex-linux-sandbox
|
|
|
|
This crate is responsible for producing:
|
|
|
|
- a `codex-linux-sandbox` standalone 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-exec` CLI can check if its arg0 is `codex-linux-sandbox` and, if so, execute as if it were `codex-linux-sandbox`
|
|
- this should also be true of the `codex` multitool CLI
|
|
|
|
On Linux, the bubblewrap pipeline prefers the system `/usr/bin/bwrap` whenever
|
|
it is available. If `/usr/bin/bwrap` is present but too old to support
|
|
`--argv0`, the helper keeps using system bubblewrap and switches to a
|
|
no-`--argv0` compatibility path for the inner re-exec. If `/usr/bin/bwrap` is
|
|
missing, the helper falls back to the vendored bubblewrap path compiled into
|
|
this binary.
|
|
Codex also surfaces a startup warning when `/usr/bin/bwrap` is missing so users
|
|
know it is falling back to the vendored helper.
|
|
|
|
**Current Behavior**
|
|
- Legacy `SandboxPolicy` / `sandbox_mode` configs remain supported.
|
|
- Bubblewrap is the default filesystem sandbox pipeline.
|
|
- If `/usr/bin/bwrap` is present, the helper uses it.
|
|
- If `/usr/bin/bwrap` is present but too old to support `--argv0`, the helper
|
|
uses a no-`--argv0` compatibility path for the inner re-exec.
|
|
- If `/usr/bin/bwrap` is missing, the helper falls back to the vendored
|
|
bubblewrap path.
|
|
- If `/usr/bin/bwrap` is missing, Codex also surfaces a startup warning instead
|
|
of printing directly from the sandbox helper.
|
|
- 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 `cwd` resolution.
|
|
- Split-only filesystem policies that do not round-trip through the legacy
|
|
`SandboxPolicy` model 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_PRIVS` and 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`,
|
|
resolved `gitdir:`, 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 = write`
|
|
keeps `/repo` writable, denies `/repo/a`, and reopens `/repo/a/b` as
|
|
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/null` on the symlink or first
|
|
missing component.
|
|
- When the default bubblewrap pipeline is active, the helper explicitly isolates the user namespace via
|
|
`--unshare-user` and 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-net` plus 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 `/proc` via `--proc /proc` by 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`.
|