Skip to content

fix: fall back to vendored bubblewrap when system bwrap lacks --argv0#15338

Open
bolinfest wants to merge 1 commit intomainfrom
pr15338
Open

fix: fall back to vendored bubblewrap when system bwrap lacks --argv0#15338
bolinfest wants to merge 1 commit intomainfrom
pr15338

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Mar 20, 2026

Why

Fixes #15283, where sandboxed tool calls fail on older distro bubblewrap builds because /usr/bin/bwrap does not understand --argv0. The upstream bubblewrap v0.9.0 release notes explicitly call out Add --argv0. Flipping use_legacy_landlock globally works around that compatibility bug, but it also weakens the default Linux sandbox and breaks proxy-routed and split-policy cases called out in review.

The follow-up Linux CI failure was in the new launcher test rather than the launcher logic: the fake bwrap helper stayed open for writing, so Linux would not exec it. This update also closes the user-visibility gap from review by surfacing the same startup warning when /usr/bin/bwrap is present but too old for --argv0, not only when it is missing.

What Changed

  • keep use_legacy_landlock default-disabled
  • teach codex-rs/linux-sandbox/src/launcher.rs to fall back to the vendored bubblewrap build when /usr/bin/bwrap does not advertise --argv0 support
  • add launcher tests for supported, unsupported, and missing system bwrap
  • write the fake bwrap test helper to a closed temp path so the supported-path launcher test works on Linux too
  • extend the startup warning path so Codex warns when /usr/bin/bwrap is missing or too old to support --argv0
  • mirror the warning/fallback wording across codex-rs/linux-sandbox/README.md and codex-rs/core/README.md, including that the fallback is the vendored bubblewrap compiled into the binary
  • cite the upstream bubblewrap release that introduced --argv0

Verification

  • bazel test --config=remote --platforms=//:rbe //codex-rs/linux-sandbox:linux-sandbox-unit-tests --test_filter=launcher::tests::prefers_system_bwrap_when_help_lists_argv0 --test_output=errors
  • cargo test -p codex-core system_bwrap_warning
  • cargo check -p codex-exec -p codex-tui -p codex-tui-app-server -p codex-app-server
  • just argument-comment-lint

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c59669d603

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

key: "use_legacy_landlock",
stage: Stage::Stable,
default_enabled: false,
default_enabled: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep bubblewrap as the default Linux sandbox

On Linux this feature value is passed directly into create_linux_sandbox_command_args_for_policies (codex-rs/core/src/sandboxing/mod.rs:676-684), so making it default-on sends normal workspace-write turns down the legacy branch in codex-rs/linux-sandbox/src/linux_run_main.rs:175-219. That legacy backend only installs the writable root paths themselves (codex-rs/linux-sandbox/src/landlock.rs:78-83), but WorkspaceWrite deliberately attaches read-only carveouts for .git, .git/hooks, .codex, etc. under each writable root (codex-rs/protocol/src/protocol.rs:786-790,932-1008). The result is a real regression in the default Linux sandbox: protected repo/config paths become writable again unless users explicitly turn this feature back off.

Useful? React with 👍 / 👎.

key: "use_legacy_landlock",
stage: Stage::Stable,
default_enabled: false,
default_enabled: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve proxy-routed networking for managed sessions

With this default flipped on, Linux managed-network runs also take the legacy Landlock branch in codex-rs/linux-sandbox/src/linux_run_main.rs:175-219. Only the bubblewrap branch prepares proxy routing and re-enters with proxy mode active; the legacy branch calls apply_sandbox_policy_to_current_thread(..., allow_network_for_proxy, false) instead, and network_seccomp_mode maps that to Restricted rather than ProxyRouted (codex-rs/linux-sandbox/src/landlock.rs:104-115). In practice, any session that depends on proxy-only outbound networking will lose network access entirely unless the user manually disables use_legacy_landlock.

Useful? React with 👍 / 👎.

key: "use_legacy_landlock",
stage: Stage::Stable,
default_enabled: false,
default_enabled: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid defaulting split FS policies to legacy Landlock

This change also makes Linux reject valid split filesystem permission profiles by default. User-defined profiles compile to FileSystemSandboxPolicy::restricted(entries) (codex-rs/core/src/config/permissions.rs:159-190), and the Linux helper explicitly panics whenever legacy mode is asked to handle a restricted policy whose semantics cannot be represented by the old sandbox model (codex-rs/linux-sandbox/src/linux_run_main.rs:383-395; codex-rs/protocol/src/permissions.rs:350-366). So configs with deny/narrowing entries that currently work under bubblewrap will start failing at runtime unless use_legacy_landlock is turned off again.

Useful? React with 👍 / 👎.

@bolinfest bolinfest changed the title fix: flip use_legacy_landlock feature so it defaults to true again fix: fall back to vendored bubblewrap when system bwrap lacks --argv0 Mar 20, 2026
@bolinfest bolinfest force-pushed the pr15338 branch 4 times, most recently from 75f47a0 to cd5d507 Compare March 20, 2026 21:45
Copy link

@evawong-oai evawong-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall direction here makes sense to me, and I appreciate the targeted compatibility fix. I left three small questions focused on validation, user visibility, and docs clarity.

Comment on lines +35 to 37
fn preferred_bwrap_launcher_for_path(system_bwrap_path: &Path) -> BubblewrapLauncher {
if !system_bwrap_supports_argv0(system_bwrap_path) {
return BubblewrapLauncher::Vendored;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me. One thing I would love to confirm before we ship is whether we have an end to end repro showing the vendored fallback succeeds on one of the older distro environments from #15283. My only hesitation is that #14919 and #14963 taught us that vendored bwrap can behave differently on some Ubuntu AppArmor hosts, so it would be reassuring to know we validated the fallback on the target environments and are not only avoiding the Unknown option --argv0 failure.

};
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
stdout.contains("--argv0") || stderr.contains("--argv0")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like there should be a better way to do this, but I'm not even sure what I'd suggest? I think this is good to merge for now!


fn preferred_bwrap_launcher_for_path(system_bwrap_path: &Path) -> BubblewrapLauncher {
if !system_bwrap_supports_argv0(system_bwrap_path) {
return BubblewrapLauncher::Vendored;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we already do, but just confirming we already vendor bubblewrap? Why not just always use the vendored version for consistency?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rreichel3-oai good question, but see #14963

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sandboxed tool calls fail on Ubuntu 20.04 with bubblewrap 0.4.0 ('bwrap: Unknown option --argv0')

3 participants