mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
## Why Network access and Unix-socket allowlists must not let commands with filesystem restrictions reach the privileged app-server RPC transport. ## What changed - Bind Unix control sockets in a fixed, user-owned directory with mode `0700`, independent of environment settings, and expose the advertised paths as symlinks. Preserve existing parent permissions, reject unsafe parents, and serialize socket setup and publication. - Mask the socket directory in Linux bubblewrap sandboxes after each bind that exposes it. Reject host mount aliases and nested mounts that compromise isolation. - Deny access to the directory and outbound connections to its sockets in macOS Seatbelt policies, including when network access or Unix-socket allowlists grant broader access. - Require bubblewrap for filesystem-restricted Linux execution. Users with `features.use_legacy_landlock` enabled must disable it for these policies. ## Testing Add regression coverage for direct and symlink socket access, hardlink attempts, Linux host-process links and bind-mount aliases, and continued use of unrelated and sandbox-local sockets. Add transport coverage for parent permissions, concurrent restart after a stale symlink, and cleanup that preserves a replacement at the advertised path. GitOrigin-RevId: 53372c27eea278d964f2cf68aed24323ef3b7082
40 lines
1.5 KiB
Rust
40 lines
1.5 KiB
Rust
//! The host-local rendezvous root for privileged app-server RPC sockets.
|
|
//!
|
|
//! Every listener uses this root, which sandboxes hide even before a daemon
|
|
//! starts. It must not depend on HOME, TMPDIR, CODEX_HOME, or command settings.
|
|
|
|
use std::fs;
|
|
use std::io;
|
|
use std::os::unix::fs::DirBuilderExt;
|
|
use std::os::unix::fs::MetadataExt;
|
|
use std::path::PathBuf;
|
|
|
|
/// Returns the fixed executor-local directory that every sandbox must hide.
|
|
pub fn shared_daemon_socket_directory() -> io::Result<PathBuf> {
|
|
// Resolve the system alias /tmp -> /private/tmp on macOS.
|
|
let temporary_root = fs::canonicalize("/tmp")?;
|
|
let uid = unsafe { libc::geteuid() };
|
|
Ok(temporary_root.join(format!("codex-daemon-{uid}")))
|
|
}
|
|
|
|
/// Creates the reserved directory, rejecting symlinks and unsafe existing owners or modes.
|
|
pub fn prepare_shared_daemon_socket_directory() -> io::Result<PathBuf> {
|
|
let directory = shared_daemon_socket_directory()?;
|
|
match fs::DirBuilder::new().mode(0o700).create(&directory) {
|
|
Ok(()) => {}
|
|
Err(error) if error.kind() == io::ErrorKind::AlreadyExists => {}
|
|
Err(error) => return Err(error),
|
|
}
|
|
let metadata = fs::symlink_metadata(&directory)?;
|
|
if !metadata.is_dir()
|
|
|| metadata.uid() != unsafe { libc::geteuid() }
|
|
|| metadata.mode() & 0o777 != 0o700
|
|
{
|
|
return Err(io::Error::new(
|
|
io::ErrorKind::PermissionDenied,
|
|
"app-server socket directory must be a user-owned directory with mode 0700",
|
|
));
|
|
}
|
|
Ok(directory)
|
|
}
|