Compare commits

...

1 Commits

Author SHA1 Message Date
starr-openai
d102cc3f03 exec-server: expose fs helper alias roots
Allow the sandboxed filesystem helper to read both the real Codex binary parent and the codex-linux-sandbox arg0 alias parent. The Docker remote-env sandbox tests also pass an in-container cwd so the remote exec-server does not try to spawn helpers from a host checkout path.

Co-authored-by: Codex <noreply@openai.com>
2026-04-22 13:18:23 -07:00
2 changed files with 112 additions and 42 deletions

View File

@@ -59,26 +59,34 @@ fn absolute_path(path: PathBuf) -> AbsolutePathBuf {
}
fn read_only_sandbox(readable_root: PathBuf) -> FileSystemSandboxContext {
FileSystemSandboxContext::new(SandboxPolicy::ReadOnly {
access: ReadOnlyAccess::Restricted {
include_platform_defaults: false,
readable_roots: vec![absolute_path(readable_root)],
let cwd = absolute_path(readable_root.clone());
FileSystemSandboxContext::from_legacy_sandbox_policy(
SandboxPolicy::ReadOnly {
access: ReadOnlyAccess::Restricted {
include_platform_defaults: false,
readable_roots: vec![absolute_path(readable_root)],
},
network_access: false,
},
network_access: false,
})
cwd,
)
}
fn workspace_write_sandbox(writable_root: PathBuf) -> FileSystemSandboxContext {
FileSystemSandboxContext::new(SandboxPolicy::WorkspaceWrite {
writable_roots: vec![absolute_path(writable_root)],
read_only_access: ReadOnlyAccess::Restricted {
include_platform_defaults: false,
readable_roots: vec![],
let cwd = absolute_path(writable_root.clone());
FileSystemSandboxContext::from_legacy_sandbox_policy(
SandboxPolicy::WorkspaceWrite {
writable_roots: vec![absolute_path(writable_root)],
read_only_access: ReadOnlyAccess::Restricted {
include_platform_defaults: false,
readable_roots: vec![],
},
network_access: false,
exclude_tmpdir_env_var: true,
exclude_slash_tmp: true,
},
network_access: false,
exclude_tmpdir_env_var: true,
exclude_slash_tmp: true,
})
cwd,
)
}
fn assert_normalized_path_rejected(error: &std::io::Error) {

View File

@@ -52,12 +52,12 @@ impl FileSystemSandboxRunner {
) -> Result<FsHelperPayload, JSONRPCErrorError> {
let cwd = sandbox_cwd(sandbox)?;
let mut file_system_policy = sandbox.permissions.file_system_sandbox_policy();
let helper_read_root = if sandbox.use_legacy_landlock {
None
let helper_read_roots = if sandbox.use_legacy_landlock {
Vec::new()
} else {
helper_read_root(&self.runtime_paths)
helper_read_roots(&self.runtime_paths)
};
add_helper_runtime_permissions(&mut file_system_policy, helper_read_root, cwd.as_path());
add_helper_runtime_permissions(&mut file_system_policy, &helper_read_roots, cwd.as_path());
normalize_file_system_policy_root_aliases(&mut file_system_policy);
let network_policy = NetworkSandboxPolicy::Restricted;
let sandbox_policy =
@@ -150,16 +150,33 @@ fn file_system_policy_has_cwd_dependent_entries(
})
}
fn helper_read_root(runtime_paths: &ExecServerRuntimePaths) -> Option<AbsolutePathBuf> {
runtime_paths
.codex_self_exe
.parent()
.and_then(|path| AbsolutePathBuf::from_absolute_path(path).ok())
fn helper_read_roots(runtime_paths: &ExecServerRuntimePaths) -> Vec<AbsolutePathBuf> {
let mut roots = Vec::new();
let helper_paths = std::iter::once(runtime_paths.codex_self_exe.as_path()).chain(
runtime_paths
.codex_linux_sandbox_exe
.as_ref()
.map(|path| path.as_path()),
);
for helper_path in helper_paths {
let Some(parent) = helper_path.parent() else {
continue;
};
let Ok(root) = AbsolutePathBuf::from_absolute_path(parent) else {
continue;
};
if !roots.contains(&root) {
roots.push(root);
}
}
roots
}
fn add_helper_runtime_permissions(
file_system_policy: &mut FileSystemSandboxPolicy,
helper_read_root: Option<AbsolutePathBuf>,
helper_read_roots: &[AbsolutePathBuf],
cwd: &std::path::Path,
) {
if !file_system_policy.has_full_disk_read_access() {
@@ -174,19 +191,18 @@ fn add_helper_runtime_permissions(
}
}
let Some(helper_read_root) = helper_read_root else {
return;
};
if file_system_policy.can_read_path_with_cwd(helper_read_root.as_path(), cwd) {
return;
}
for helper_read_root in helper_read_roots {
if file_system_policy.can_read_path_with_cwd(helper_read_root.as_path(), cwd) {
continue;
}
file_system_policy.entries.push(FileSystemSandboxEntry {
path: FileSystemPath::Path {
path: helper_read_root,
},
access: FileSystemAccessMode::Read,
});
file_system_policy.entries.push(FileSystemSandboxEntry {
path: FileSystemPath::Path {
path: helper_read_root.clone(),
},
access: FileSystemAccessMode::Read,
});
}
}
fn compatibility_sandbox_policy(
@@ -371,7 +387,7 @@ mod tests {
use super::helper_env;
use super::helper_env_from_vars;
use super::helper_env_key_is_allowed;
use super::helper_read_root;
use super::helper_read_roots;
use super::sandbox_cwd;
#[test]
@@ -388,7 +404,7 @@ mod tests {
let mut policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, cwd.as_path());
add_helper_runtime_permissions(&mut policy, /*helper_read_root*/ None, cwd.as_path());
add_helper_runtime_permissions(&mut policy, &[], cwd.as_path());
assert!(policy.include_platform_defaults());
}
@@ -410,7 +426,7 @@ mod tests {
let mut policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, cwd.as_path());
add_helper_runtime_permissions(&mut policy, /*helper_read_root*/ None, cwd.as_path());
add_helper_runtime_permissions(&mut policy, &[], cwd.as_path());
assert!(policy.include_platform_defaults());
}
@@ -449,7 +465,7 @@ mod tests {
add_helper_runtime_permissions(
&mut policy,
helper_read_root(&runtime_paths),
&helper_read_roots(&runtime_paths),
cwd.as_path(),
);
@@ -611,10 +627,56 @@ mod tests {
add_helper_runtime_permissions(
&mut policy,
helper_read_root(&runtime_paths),
&helper_read_roots(&runtime_paths),
cwd.as_path(),
);
assert!(policy.can_read_path_with_cwd(readable.as_path(), cwd.as_path()));
}
#[test]
fn helper_permissions_include_linux_sandbox_alias_root() {
let temp_dir = tempfile::tempdir().expect("temp dir");
let codex_self_exe = temp_dir.path().join("remote-env").join("codex");
let codex_linux_sandbox_exe = temp_dir
.path()
.join("arg0")
.join("codex-session")
.join("codex-linux-sandbox");
let runtime_paths = ExecServerRuntimePaths::new(
codex_self_exe.clone(),
Some(codex_linux_sandbox_exe.clone()),
)
.expect("runtime paths");
let cwd = AbsolutePathBuf::from_absolute_path(std::env::temp_dir().as_path())
.expect("absolute cwd");
let sandbox_policy = SandboxPolicy::ReadOnly {
access: ReadOnlyAccess::Restricted {
include_platform_defaults: false,
readable_roots: Vec::new(),
},
network_access: false,
};
let mut policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, cwd.as_path());
let codex_self_root = AbsolutePathBuf::from_absolute_path(
codex_self_exe.parent().expect("codex self parent"),
)
.expect("codex self root should be absolute");
let linux_sandbox_root = AbsolutePathBuf::from_absolute_path(
codex_linux_sandbox_exe
.parent()
.expect("linux sandbox parent"),
)
.expect("linux sandbox root should be absolute");
add_helper_runtime_permissions(
&mut policy,
&helper_read_roots(&runtime_paths),
cwd.as_path(),
);
assert!(policy.can_read_path_with_cwd(codex_self_root.as_path(), cwd.as_path()));
assert!(policy.can_read_path_with_cwd(linux_sandbox_root.as_path(), cwd.as_path()));
}
}