From 2023456ccf642d5ae6694d49520c05f6e485a0ce Mon Sep 17 00:00:00 2001 From: Eva Wong Date: Wed, 6 May 2026 17:25:22 -0700 Subject: [PATCH] Remove Darwin user cache Seatbelt write --- codex-rs/sandboxing/src/seatbelt.rs | 28 ------------- .../src/seatbelt_network_policy.sbpl | 6 +-- codex-rs/sandboxing/src/seatbelt_tests.rs | 40 +++++++++++-------- 3 files changed, 24 insertions(+), 50 deletions(-) diff --git a/codex-rs/sandboxing/src/seatbelt.rs b/codex-rs/sandboxing/src/seatbelt.rs index 9383c77b3ad5..7057ec46b96a 100644 --- a/codex-rs/sandboxing/src/seatbelt.rs +++ b/codex-rs/sandboxing/src/seatbelt.rs @@ -12,7 +12,6 @@ use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashMap; use std::collections::VecDeque; -use std::ffi::CStr; use std::path::Path; use std::path::PathBuf; use tracing::warn; @@ -725,7 +724,6 @@ pub fn create_seatbelt_command_args(args: CreateSeatbeltCommandArgsParams<'_>) - let dir_params = [ file_read_dir_params, file_write_dir_params, - macos_dir_params(), unix_socket_dir_params(&proxy), ] .concat(); @@ -742,32 +740,6 @@ pub fn create_seatbelt_command_args(args: CreateSeatbeltCommandArgsParams<'_>) - seatbelt_args } -/// Wraps libc::confstr to return a String. -fn confstr(name: libc::c_int) -> Option { - let mut buf = vec![0_i8; (libc::PATH_MAX as usize) + 1]; - let len = unsafe { libc::confstr(name, buf.as_mut_ptr(), buf.len()) }; - if len == 0 { - return None; - } - // confstr guarantees NUL-termination when len > 0. - let cstr = unsafe { CStr::from_ptr(buf.as_ptr()) }; - cstr.to_str().ok().map(ToString::to_string) -} - -/// Wraps confstr to return a canonicalized PathBuf. -fn confstr_path(name: libc::c_int) -> Option { - let s = confstr(name)?; - let path = PathBuf::from(s); - path.canonicalize().ok().or(Some(path)) -} - -fn macos_dir_params() -> Vec<(String, PathBuf)> { - if let Some(p) = confstr_path(libc::_CS_DARWIN_USER_CACHE_DIR) { - return vec![("DARWIN_USER_CACHE_DIR".to_string(), p)]; - } - vec![] -} - #[cfg(test)] #[path = "seatbelt_tests.rs"] mod tests; diff --git a/codex-rs/sandboxing/src/seatbelt_network_policy.sbpl b/codex-rs/sandboxing/src/seatbelt_network_policy.sbpl index a0801d093b5a..1bb9eb2b82aa 100644 --- a/codex-rs/sandboxing/src/seatbelt_network_policy.sbpl +++ b/codex-rs/sandboxing/src/seatbelt_network_policy.sbpl @@ -11,7 +11,7 @@ ) (allow mach-lookup - ; Used to look up the _CS_DARWIN_USER_CACHE_DIR in the sandbox. + ; Used by platform helpers that resolve user directory locations. (global-name "com.apple.bsd.dirhelper") (global-name "com.apple.system.opendirectoryd.membership") @@ -29,7 +29,3 @@ (allow sysctl-read (sysctl-name-regex #"^net.routetable") ) - -(allow file-write* - (subpath (param "DARWIN_USER_CACHE_DIR")) -) diff --git a/codex-rs/sandboxing/src/seatbelt_tests.rs b/codex-rs/sandboxing/src/seatbelt_tests.rs index a8f14fc26a0f..ecaea5d9af17 100644 --- a/codex-rs/sandboxing/src/seatbelt_tests.rs +++ b/codex-rs/sandboxing/src/seatbelt_tests.rs @@ -7,7 +7,6 @@ use super::build_seatbelt_unreadable_glob_policy; use super::create_seatbelt_command_args; use super::create_seatbelt_command_args_for_legacy_policy; use super::dynamic_network_policy; -use super::macos_dir_params; use super::normalize_path_for_sandbox; use super::seatbelt_regex_for_unreadable_glob; use super::unix_socket_dir_params; @@ -161,6 +160,29 @@ fn create_seatbelt_args_routes_network_through_proxy_ports() { ); } +#[test] +fn dynamic_network_policy_allows_tls_without_darwin_user_cache_write() { + let policy = dynamic_network_policy( + &SandboxPolicy::WorkspaceWrite { + writable_roots: vec![], + network_access: true, + exclude_tmpdir_env_var: false, + exclude_slash_tmp: false, + }, + /*enforce_managed_network*/ false, + &ProxyPolicyInputs::default(), + ); + + assert!( + policy.contains("(global-name \"com.apple.trustd.agent\")"), + "policy should keep trustd agent access for TLS certificate verification:\n{policy}" + ); + assert!( + !policy.contains("DARWIN_USER_CACHE_DIR"), + "network policy should not grant broad user cache writes:\n{policy}" + ); +} + #[test] fn explicit_unreadable_paths_are_excluded_from_full_disk_read_and_write_access() { let unreadable = absolute_path("/tmp/codex-unreadable"); @@ -941,14 +963,6 @@ fn create_seatbelt_args_with_read_only_git_and_codex_subpaths() { writable_definitions, expected_definitions, "unexpected writable-root parameter definitions in {args:#?}" ); - for (key, value) in macos_dir_params() { - let expected_definition = format!("-D{key}={}", value.to_string_lossy()); - assert!( - args.contains(&expected_definition), - "expected definition arg `{expected_definition}` in {args:#?}" - ); - } - let command_index = args .iter() .position(|arg| arg == "--") @@ -1311,14 +1325,6 @@ fn create_seatbelt_args_for_cwd_as_git_repo() { args.contains(&expected_slash_tmp), "missing {expected_slash_tmp}: {args:#?}" ); - for (key, value) in macos_dir_params() { - let expected_definition = format!("-D{key}={}", value.to_string_lossy()); - assert!( - args.contains(&expected_definition), - "expected definition arg `{expected_definition}` in {args:#?}" - ); - } - let command_index = args .iter() .position(|arg| arg == "--")