mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
fix: close only exec-inheritable fds before sandbox exec
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -1,49 +1,20 @@
|
||||
//! File descriptor hygiene before entering the sandboxed command.
|
||||
|
||||
/// Mark helper-inherited descriptors close-on-exec unless they are standard
|
||||
/// input/output/error.
|
||||
/// Close helper-inherited descriptors unless they are standard input/output/error
|
||||
/// or already close-on-exec.
|
||||
///
|
||||
/// The sandboxed command can still create allowed local IPC after exec, but it
|
||||
/// must not inherit an already-connected network socket from the launcher.
|
||||
pub(crate) fn mark_inherited_fds_cloexec() {
|
||||
match set_cloexec_with_close_range() {
|
||||
Ok(()) => return,
|
||||
Err(err) if can_fallback_from_close_range(&err) => {}
|
||||
Err(err) => panic!("failed to mark inherited file descriptors close-on-exec: {err}"),
|
||||
}
|
||||
|
||||
pub(crate) fn close_inherited_exec_fds() {
|
||||
let fds = match non_stdio_fds_from_proc() {
|
||||
Ok(fds) => fds,
|
||||
Err(err) => panic!("failed to enumerate inherited file descriptors: {err}"),
|
||||
};
|
||||
for fd in fds {
|
||||
set_fd_cloexec_ignoring_badf(fd);
|
||||
close_fd_if_inheritable(fd);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_cloexec_with_close_range() -> std::io::Result<()> {
|
||||
let result = unsafe {
|
||||
libc::syscall(
|
||||
libc::SYS_close_range,
|
||||
(libc::STDERR_FILENO + 1) as libc::c_uint,
|
||||
u32::MAX as libc::c_uint,
|
||||
libc::CLOSE_RANGE_CLOEXEC,
|
||||
)
|
||||
};
|
||||
if result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(std::io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
fn can_fallback_from_close_range(err: &std::io::Error) -> bool {
|
||||
matches!(
|
||||
err.raw_os_error(),
|
||||
Some(code) if code == libc::ENOSYS || code == libc::EPERM || code == libc::EINVAL
|
||||
)
|
||||
}
|
||||
|
||||
fn non_stdio_fds_from_proc() -> std::io::Result<Vec<libc::c_int>> {
|
||||
let mut fds = Vec::new();
|
||||
for entry in std::fs::read_dir("/proc/self/fd")? {
|
||||
@@ -62,7 +33,7 @@ fn non_stdio_fds_from_proc() -> std::io::Result<Vec<libc::c_int>> {
|
||||
Ok(fds)
|
||||
}
|
||||
|
||||
fn set_fd_cloexec_ignoring_badf(fd: libc::c_int) {
|
||||
fn close_fd_if_inheritable(fd: libc::c_int) {
|
||||
let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
|
||||
if flags == -1 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
@@ -71,12 +42,15 @@ fn set_fd_cloexec_ignoring_badf(fd: libc::c_int) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if flags & libc::FD_CLOEXEC != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = unsafe { libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
|
||||
if result == -1 {
|
||||
let result = unsafe { libc::close(fd) };
|
||||
if result != 0 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
if err.raw_os_error() != Some(libc::EBADF) {
|
||||
panic!("failed to mark inherited file descriptor {fd} close-on-exec: {err}");
|
||||
panic!("failed to close inherited file descriptor {fd}: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::path::PathBuf;
|
||||
use crate::bwrap::BwrapNetworkMode;
|
||||
use crate::bwrap::BwrapOptions;
|
||||
use crate::bwrap::create_bwrap_command_args;
|
||||
use crate::fd_cleanup::mark_inherited_fds_cloexec;
|
||||
use crate::fd_cleanup::close_inherited_exec_fds;
|
||||
use crate::landlock::apply_sandbox_policy_to_current_thread;
|
||||
use crate::launcher::exec_bwrap;
|
||||
use crate::launcher::preferred_bwrap_supports_argv0;
|
||||
@@ -730,7 +730,7 @@ fn exec_or_panic(command: Vec<String>) -> ! {
|
||||
let mut c_args_ptrs: Vec<*const libc::c_char> = c_args.iter().map(|arg| arg.as_ptr()).collect();
|
||||
c_args_ptrs.push(std::ptr::null());
|
||||
|
||||
mark_inherited_fds_cloexec();
|
||||
close_inherited_exec_fds();
|
||||
|
||||
unsafe {
|
||||
libc::execvp(c_command.as_ptr(), c_args_ptrs.as_ptr());
|
||||
|
||||
Reference in New Issue
Block a user