never let sandbox write to .codex/ or .codex/.sandbox/ (#8683)
Never treat .codex or .codex/.sandbox as a workspace root. Handle write permissions to .codex/.sandbox in a single method so that the sandbox setup/runner can write logs and other setup files to that directory.
This commit is contained in:
parent
720fa67816
commit
95580f229e
3 changed files with 21 additions and 9 deletions
|
|
@ -30,7 +30,7 @@ const SKIP_DIR_SUFFIXES: &[&str] = &[
|
|||
"/programdata",
|
||||
];
|
||||
|
||||
fn normalize_path_key(p: &Path) -> String {
|
||||
pub(crate) fn normalize_path_key(p: &Path) -> String {
|
||||
let n = dunce::canonicalize(p).unwrap_or_else(|_| p.to_path_buf());
|
||||
n.to_string_lossy().replace('\\', "/").to_ascii_lowercase()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,9 +119,10 @@ pub fn require_logon_sandbox_creds(
|
|||
) -> Result<SandboxCreds> {
|
||||
let sandbox_dir = crate::setup::sandbox_dir(codex_home);
|
||||
let needed_read = gather_read_roots(command_cwd, policy);
|
||||
let mut needed_write = gather_write_roots(policy, policy_cwd, command_cwd, env_map);
|
||||
// Ensure the sandbox directory itself is writable by sandbox users.
|
||||
needed_write.push(sandbox_dir.clone());
|
||||
let needed_write = gather_write_roots(policy, policy_cwd, command_cwd, env_map);
|
||||
// NOTE: Do not add CODEX_HOME/.sandbox to `needed_write`; it must remain non-writable by the
|
||||
// restricted capability token. The setup helper's `lock_sandbox_dir` is responsible for
|
||||
// granting the sandbox group access to this directory without granting the capability SID.
|
||||
let mut setup_reason: Option<String> = None;
|
||||
let mut _existing_marker: Option<SetupMarker> = None;
|
||||
|
||||
|
|
|
|||
|
|
@ -408,15 +408,12 @@ fn build_payload_roots(
|
|||
read_roots_override: Option<Vec<PathBuf>>,
|
||||
write_roots_override: Option<Vec<PathBuf>>,
|
||||
) -> (Vec<PathBuf>, Vec<PathBuf>) {
|
||||
let sbx_dir = sandbox_dir(codex_home);
|
||||
let mut write_roots = if let Some(roots) = write_roots_override {
|
||||
let write_roots = if let Some(roots) = write_roots_override {
|
||||
canonical_existing(&roots)
|
||||
} else {
|
||||
gather_write_roots(policy, policy_cwd, command_cwd, env_map)
|
||||
};
|
||||
if !write_roots.contains(&sbx_dir) {
|
||||
write_roots.push(sbx_dir.clone());
|
||||
}
|
||||
let write_roots = filter_sensitive_write_roots(write_roots, codex_home);
|
||||
let mut read_roots = if let Some(roots) = read_roots_override {
|
||||
canonical_existing(&roots)
|
||||
} else {
|
||||
|
|
@ -426,3 +423,17 @@ fn build_payload_roots(
|
|||
read_roots.retain(|root| !write_root_set.contains(root));
|
||||
(read_roots, write_roots)
|
||||
}
|
||||
|
||||
fn filter_sensitive_write_roots(mut roots: Vec<PathBuf>, codex_home: &Path) -> Vec<PathBuf> {
|
||||
// Never grant capability write access to CODEX_HOME or anything under CODEX_HOME/.sandbox.
|
||||
// These locations contain sandbox control/state and must remain tamper-resistant.
|
||||
let codex_home_key = crate::audit::normalize_path_key(codex_home);
|
||||
let sbx_dir_key = crate::audit::normalize_path_key(&sandbox_dir(codex_home));
|
||||
let sbx_dir_prefix = format!("{}/", sbx_dir_key.trim_end_matches('/'));
|
||||
|
||||
roots.retain(|root| {
|
||||
let key = crate::audit::normalize_path_key(root);
|
||||
key != codex_home_key && key != sbx_dir_key && !key.starts_with(&sbx_dir_prefix)
|
||||
});
|
||||
roots
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue