-
Notifications
You must be signed in to change notification settings - Fork 10.9k
fix(linux-sandbox): prefer system /usr/bin/bwrap when available #14963
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
viyatb-oai
merged 16 commits into
main
from
codex/viyatb/document-apparmor-profile-for-bwrap
Mar 17, 2026
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
f4aed0f
Prefer system bwrap on AppArmor hosts
viyatb-oai bb7de07
fix(linux-sandbox): prefer system bwrap when available
viyatb-oai acad347
fix(linux-sandbox): remove stale vendored bwrap export
viyatb-oai 1a44c08
refactor(linux-sandbox): inline bwrap launcher selector
viyatb-oai 42005af
fix(linux-sandbox): tighten system bwrap launcher
viyatb-oai 914e69f
fix(linux-sandbox): route missing bwrap warning upstream
viyatb-oai b4ae458
fix(linux-sandbox): simplify missing bwrap warning
viyatb-oai 6cbdf45
fix(linux-sandbox): share missing bwrap warning
viyatb-oai 7d0f0cb
fix(linux-sandbox): finalize shared bwrap warning
viyatb-oai b015baf
refactor(linux-sandbox): inline bwrap startup warning
viyatb-oai 00edde7
refactor(linux-sandbox): reorder bwrap startup warning
viyatb-oai 225434b
fix(linux-sandbox): scope bwrap warning to startup surfaces
viyatb-oai ee4c028
fix(linux-sandbox): avoid expect in launcher
viyatb-oai 00b7d98
fix(exec): suppress bwrap warning in json mode
viyatb-oai c2a9cd5
Merge remote-tracking branch 'origin/main' into codex/viyatb/document…
viyatb-oai d9f8614
Merge branch 'main' into codex/viyatb/document-apparmor-profile-for-b…
viyatb-oai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| use std::ffi::CString; | ||
| use std::fs::File; | ||
| use std::os::fd::AsRawFd; | ||
| use std::os::raw::c_char; | ||
| use std::os::unix::ffi::OsStrExt; | ||
| use std::path::Path; | ||
|
|
||
| use crate::vendored_bwrap::exec_vendored_bwrap; | ||
| use codex_utils_absolute_path::AbsolutePathBuf; | ||
|
|
||
| const SYSTEM_BWRAP_PATH: &str = "/usr/bin/bwrap"; | ||
|
|
||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| enum BubblewrapLauncher { | ||
| System(AbsolutePathBuf), | ||
| Vendored, | ||
| } | ||
|
|
||
| pub(crate) fn exec_bwrap(argv: Vec<String>, preserved_files: Vec<File>) -> ! { | ||
| match preferred_bwrap_launcher() { | ||
| BubblewrapLauncher::System(program) => exec_system_bwrap(&program, argv, preserved_files), | ||
| BubblewrapLauncher::Vendored => exec_vendored_bwrap(argv, preserved_files), | ||
| } | ||
| } | ||
|
|
||
| fn preferred_bwrap_launcher() -> BubblewrapLauncher { | ||
| if !Path::new(SYSTEM_BWRAP_PATH).is_file() { | ||
| return BubblewrapLauncher::Vendored; | ||
| } | ||
|
|
||
| let system_bwrap_path = match AbsolutePathBuf::from_absolute_path(SYSTEM_BWRAP_PATH) { | ||
| Ok(path) => path, | ||
| Err(err) => panic!("failed to normalize system bubblewrap path {SYSTEM_BWRAP_PATH}: {err}"), | ||
| }; | ||
| BubblewrapLauncher::System(system_bwrap_path) | ||
| } | ||
|
|
||
| fn exec_system_bwrap( | ||
| program: &AbsolutePathBuf, | ||
| argv: Vec<String>, | ||
| preserved_files: Vec<File>, | ||
| ) -> ! { | ||
| // System bwrap runs across an exec boundary, so preserved fds must survive exec. | ||
| make_files_inheritable(&preserved_files); | ||
|
|
||
| let program_path = program.as_path().display().to_string(); | ||
| let program = CString::new(program.as_path().as_os_str().as_bytes()) | ||
| .unwrap_or_else(|err| panic!("invalid system bubblewrap path: {err}")); | ||
| let cstrings = argv_to_cstrings(&argv); | ||
| let mut argv_ptrs: Vec<*const c_char> = cstrings.iter().map(|arg| arg.as_ptr()).collect(); | ||
| argv_ptrs.push(std::ptr::null()); | ||
|
|
||
| // SAFETY: `program` and every entry in `argv_ptrs` are valid C strings for | ||
| // the duration of the call. On success `execv` does not return. | ||
| unsafe { | ||
| libc::execv(program.as_ptr(), argv_ptrs.as_ptr()); | ||
| } | ||
| let err = std::io::Error::last_os_error(); | ||
| panic!("failed to exec system bubblewrap {program_path}: {err}"); | ||
| } | ||
|
|
||
| fn argv_to_cstrings(argv: &[String]) -> Vec<CString> { | ||
| let mut cstrings: Vec<CString> = Vec::with_capacity(argv.len()); | ||
| for arg in argv { | ||
| match CString::new(arg.as_str()) { | ||
| Ok(value) => cstrings.push(value), | ||
| Err(err) => panic!("failed to convert argv to CString: {err}"), | ||
| } | ||
| } | ||
| cstrings | ||
| } | ||
|
|
||
| fn make_files_inheritable(files: &[File]) { | ||
| for file in files { | ||
| clear_cloexec(file.as_raw_fd()); | ||
| } | ||
| } | ||
|
|
||
| fn clear_cloexec(fd: libc::c_int) { | ||
| // SAFETY: `fd` is an owned descriptor kept alive by `files`. | ||
| let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) }; | ||
| if flags < 0 { | ||
| let err = std::io::Error::last_os_error(); | ||
| panic!("failed to read fd flags for preserved bubblewrap file descriptor {fd}: {err}"); | ||
| } | ||
| let cleared_flags = flags & !libc::FD_CLOEXEC; | ||
| if cleared_flags == flags { | ||
| return; | ||
| } | ||
|
|
||
| // SAFETY: `fd` is valid and we are only clearing FD_CLOEXEC. | ||
| let result = unsafe { libc::fcntl(fd, libc::F_SETFD, cleared_flags) }; | ||
| if result < 0 { | ||
| let err = std::io::Error::last_os_error(); | ||
| panic!("failed to clear CLOEXEC for preserved bubblewrap file descriptor {fd}: {err}"); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
| use pretty_assertions::assert_eq; | ||
| use tempfile::NamedTempFile; | ||
|
|
||
| #[test] | ||
| fn preserved_files_are_made_inheritable_for_system_exec() { | ||
| let file = NamedTempFile::new().expect("temp file"); | ||
| set_cloexec(file.as_file().as_raw_fd()); | ||
|
|
||
| make_files_inheritable(std::slice::from_ref(file.as_file())); | ||
|
|
||
| assert_eq!(fd_flags(file.as_file().as_raw_fd()) & libc::FD_CLOEXEC, 0); | ||
| } | ||
|
|
||
| fn set_cloexec(fd: libc::c_int) { | ||
| let flags = fd_flags(fd); | ||
| // SAFETY: `fd` is valid for the duration of the test. | ||
| let result = unsafe { libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) }; | ||
| if result < 0 { | ||
| let err = std::io::Error::last_os_error(); | ||
| panic!("failed to set CLOEXEC for test fd {fd}: {err}"); | ||
| } | ||
| } | ||
|
|
||
| fn fd_flags(fd: libc::c_int) -> libc::c_int { | ||
| // SAFETY: `fd` is valid for the duration of the test. | ||
| let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) }; | ||
| if flags < 0 { | ||
| let err = std::io::Error::last_os_error(); | ||
| panic!("failed to read fd flags for test fd {fd}: {err}"); | ||
| } | ||
| flags | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,4 +76,3 @@ Notes: | |
| } | ||
|
|
||
| pub(crate) use imp::exec_vendored_bwrap; | ||
| pub(crate) use imp::run_vendored_bwrap_main; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.