Compare commits

...

1 Commits

Author SHA1 Message Date
David Wiesen
f0ea745277 Fallback to vendored bwrap without --argv0 support 2026-03-21 10:34:32 -07:00
2 changed files with 39 additions and 5 deletions

View File

@@ -8,17 +8,18 @@ This crate is responsible for producing:
- 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 missing, the helper still falls back to
the vendored bubblewrap path compiled into this binary.
it is available and supports the flags Codex requires. If `/usr/bin/bwrap` is
missing or too old to support `--argv0`, 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 missing, the helper falls back to the vendored
bubblewrap path.
- If `/usr/bin/bwrap` is present and supports `--argv0`, the helper uses it.
- If `/usr/bin/bwrap` is missing or too old to support `--argv0`, 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

View File

@@ -4,6 +4,7 @@ use std::os::fd::AsRawFd;
use std::os::raw::c_char;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::process::Command;
use crate::vendored_bwrap::exec_vendored_bwrap;
use codex_utils_absolute_path::AbsolutePathBuf;
@@ -32,9 +33,27 @@ fn preferred_bwrap_launcher() -> BubblewrapLauncher {
Ok(path) => path,
Err(err) => panic!("failed to normalize system bubblewrap path {SYSTEM_BWRAP_PATH}: {err}"),
};
if !system_bwrap_supports_argv0(system_bwrap_path.as_path()) {
return BubblewrapLauncher::Vendored;
}
BubblewrapLauncher::System(system_bwrap_path)
}
fn system_bwrap_supports_argv0(path: &Path) -> bool {
let output = Command::new(path).arg("--help").output();
let Ok(output) = output else {
return false;
};
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
help_output_supports_argv0(stdout.as_ref()) || help_output_supports_argv0(stderr.as_ref())
}
fn help_output_supports_argv0(output: &str) -> bool {
output.lines().any(|line| line.contains("--argv0"))
}
fn exec_system_bwrap(
program: &AbsolutePathBuf,
argv: Vec<String>,
@@ -112,6 +131,20 @@ mod tests {
assert_eq!(fd_flags(file.as_file().as_raw_fd()) & libc::FD_CLOEXEC, 0);
}
#[test]
fn detects_argv0_support_from_help_output() {
assert!(help_output_supports_argv0(
"Usage: bwrap [OPTIONS]\n --argv0 VALUE Set argv[0]\n"
));
}
#[test]
fn rejects_help_output_without_argv0() {
assert!(!help_output_supports_argv0(
"Usage: bwrap [OPTIONS]\n --proc DEST Mount proc\n"
));
}
fn set_cloexec(fd: libc::c_int) {
let flags = fd_flags(fd);
// SAFETY: `fd` is valid for the duration of the test.