mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
refactor(permissions): lower Linux enforcement from effective filesystem permissions
Co-authored-by: Codex noreply@openai.com
This commit is contained in:
co-authored by
Codex noreply@openai.com
parent
0dc8cf86c9
commit
2ab25cb2c5
@@ -27,11 +27,8 @@ use std::process::Command;
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::Result;
|
||||
use codex_protocol::permissions::is_protected_metadata_name;
|
||||
use codex_protocol::protocol::FileSystemAccessMode;
|
||||
use codex_protocol::protocol::FileSystemPath;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::FileSystemSpecialPath;
|
||||
use codex_protocol::protocol::WritableRoot;
|
||||
use codex_sandboxing::EffectiveFilesystemPermissions;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use globset::GlobBuilder;
|
||||
use globset::GlobSet;
|
||||
@@ -233,16 +230,16 @@ impl SyntheticMountTarget {
|
||||
/// namespace restrictions apply while preserving full filesystem access.
|
||||
pub(crate) fn create_bwrap_command_args(
|
||||
command: Vec<String>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
options: BwrapOptions,
|
||||
) -> Result<BwrapArgs> {
|
||||
let unreadable_globs =
|
||||
file_system_sandbox_policy.get_unreadable_globs_with_cwd(sandbox_policy_cwd);
|
||||
// Full disk write normally skips bwrap, but unreadable glob patterns still
|
||||
// need concrete bwrap masks for the matches expanded below.
|
||||
if file_system_sandbox_policy.has_full_disk_write_access() && unreadable_globs.is_empty() {
|
||||
if effective_filesystem_permissions.has_full_disk_write_access()
|
||||
&& effective_filesystem_permissions.unreadable_globs.is_empty()
|
||||
{
|
||||
return if options.network_mode == BwrapNetworkMode::FullAccess {
|
||||
Ok(BwrapArgs {
|
||||
args: command,
|
||||
@@ -257,7 +254,7 @@ pub(crate) fn create_bwrap_command_args(
|
||||
|
||||
create_bwrap_flags(
|
||||
command,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
options,
|
||||
@@ -296,7 +293,7 @@ fn create_bwrap_flags_full_filesystem(command: Vec<String>, options: BwrapOption
|
||||
/// Build the bubblewrap flags (everything after `argv[0]`).
|
||||
fn create_bwrap_flags(
|
||||
command: Vec<String>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
options: BwrapOptions,
|
||||
@@ -306,12 +303,12 @@ fn create_bwrap_flags(
|
||||
preserved_files,
|
||||
synthetic_mount_targets,
|
||||
protected_create_targets,
|
||||
} = create_filesystem_args(
|
||||
file_system_sandbox_policy,
|
||||
} = create_effective_filesystem_args(
|
||||
effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
options
|
||||
.glob_scan_max_depth
|
||||
.or(file_system_sandbox_policy.glob_scan_max_depth),
|
||||
.or(effective_filesystem_permissions.glob_scan_max_depth),
|
||||
)?;
|
||||
let normalized_command_cwd = normalize_command_cwd_for_bwrap(command_cwd);
|
||||
let mut args = Vec::new();
|
||||
@@ -364,22 +361,27 @@ fn create_bwrap_flags(
|
||||
/// those writable roots so protected subpaths win.
|
||||
/// 6. Nested unreadable carveouts under a writable root are masked after that
|
||||
/// root is bound, and unrelated unreadable roots are masked afterward.
|
||||
fn create_filesystem_args(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
fn create_effective_filesystem_args(
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
cwd: &Path,
|
||||
glob_scan_max_depth: Option<usize>,
|
||||
) -> Result<BwrapArgs> {
|
||||
let unreadable_globs = file_system_sandbox_policy.get_unreadable_globs_with_cwd(cwd);
|
||||
let unreadable_globs = effective_filesystem_permissions
|
||||
.unreadable_globs
|
||||
.iter()
|
||||
.map(|glob| glob.pattern().to_string())
|
||||
.collect::<Vec<_>>();
|
||||
// Bubblewrap requires bind mount targets to exist. Skip missing writable
|
||||
// roots so mixed-platform configs can keep harmless paths for other
|
||||
// environments without breaking Linux command startup.
|
||||
let mut writable_roots = file_system_sandbox_policy
|
||||
.get_writable_roots_with_cwd(cwd)
|
||||
.into_iter()
|
||||
let mut writable_roots = effective_filesystem_permissions
|
||||
.writable_roots
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|writable_root| writable_root.root.as_path().exists())
|
||||
.collect::<Vec<_>>();
|
||||
if writable_roots.is_empty()
|
||||
&& file_system_sandbox_policy.has_full_disk_write_access()
|
||||
&& effective_filesystem_permissions.has_full_disk_write_access()
|
||||
&& !unreadable_globs.is_empty()
|
||||
{
|
||||
writable_roots.push(WritableRoot {
|
||||
@@ -388,42 +390,10 @@ fn create_filesystem_args(
|
||||
protected_metadata_names: Vec::new(),
|
||||
});
|
||||
}
|
||||
let missing_auto_metadata_read_only_project_root_subpaths: HashSet<PathBuf> =
|
||||
file_system_sandbox_policy
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Read)
|
||||
.filter_map(|entry| {
|
||||
let FileSystemPath::Special {
|
||||
value:
|
||||
FileSystemSpecialPath::ProjectRoots {
|
||||
subpath: Some(subpath),
|
||||
},
|
||||
} = &entry.path
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
// Automatic repo-metadata read masks are skipped here so the
|
||||
// metadata handling below can apply the root-scoped
|
||||
// protection consistently for `.git`, `.agents`, and `.codex`.
|
||||
// User-authored `read` rules for other subpaths and `none`
|
||||
// rules should keep their normal bwrap behavior, which can mask
|
||||
// the first missing component to prevent creation under writable
|
||||
// roots.
|
||||
let project_subpath = subpath.as_path();
|
||||
if project_subpath != Path::new(".git")
|
||||
&& project_subpath != Path::new(".agents")
|
||||
&& project_subpath != Path::new(".codex")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let resolved = AbsolutePathBuf::resolve_path_against_base(subpath, cwd);
|
||||
(!resolved.as_path().exists()).then(|| resolved.into_path_buf())
|
||||
})
|
||||
.collect();
|
||||
let mut unreadable_roots = file_system_sandbox_policy
|
||||
.get_unreadable_roots_with_cwd(cwd)
|
||||
.into_iter()
|
||||
let mut unreadable_roots = effective_filesystem_permissions
|
||||
.unreadable_roots
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(AbsolutePathBuf::into_path_buf)
|
||||
.collect::<Vec<_>>();
|
||||
// Bubblewrap can only mask concrete paths. Expand unreadable glob patterns
|
||||
@@ -437,7 +407,7 @@ fn create_filesystem_args(
|
||||
unreadable_roots.sort();
|
||||
unreadable_roots.dedup();
|
||||
|
||||
let args = if file_system_sandbox_policy.has_full_disk_read_access() {
|
||||
let args = if effective_filesystem_permissions.has_full_disk_read_access() {
|
||||
// Read-only root, then mount a minimal device tree.
|
||||
// In bubblewrap (`bubblewrap.c`, `SETUP_MOUNT_DEV`), `--dev /dev`
|
||||
// creates the standard minimal nodes: null, zero, full, random,
|
||||
@@ -460,12 +430,13 @@ fn create_filesystem_args(
|
||||
"/dev".to_string(),
|
||||
];
|
||||
|
||||
let mut readable_roots: BTreeSet<PathBuf> = file_system_sandbox_policy
|
||||
.get_readable_roots_with_cwd(cwd)
|
||||
.into_iter()
|
||||
let mut readable_roots: BTreeSet<PathBuf> = effective_filesystem_permissions
|
||||
.readable_roots
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(PathBuf::from)
|
||||
.collect();
|
||||
if file_system_sandbox_policy.include_platform_defaults() {
|
||||
if effective_filesystem_permissions.include_platform_defaults {
|
||||
readable_roots.extend(
|
||||
LINUX_PLATFORM_DEFAULT_READ_ROOTS
|
||||
.iter()
|
||||
@@ -573,7 +544,6 @@ fn create_filesystem_args(
|
||||
.iter()
|
||||
.map(|path| path.as_path().to_path_buf())
|
||||
.filter(|path| !unreadable_paths.contains(path))
|
||||
.filter(|path| !missing_auto_metadata_read_only_project_root_subpaths.contains(path))
|
||||
.collect();
|
||||
let protected_metadata_names = writable_root.protected_metadata_names.clone();
|
||||
append_metadata_path_masks_for_writable_root(
|
||||
@@ -1324,6 +1294,61 @@ fn find_first_non_existent_component(target_path: &Path) -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn effective_test_filesystem_permissions(
|
||||
file_system_sandbox_policy: &codex_protocol::protocol::FileSystemSandboxPolicy,
|
||||
cwd: &Path,
|
||||
) -> EffectiveFilesystemPermissions {
|
||||
let cwd = AbsolutePathBuf::from_absolute_path(cwd)
|
||||
.unwrap_or_else(|err| panic!("test policy cwd should be absolute: {err}"));
|
||||
let file_system_sandbox_policy = file_system_sandbox_policy
|
||||
.clone()
|
||||
.materialize_project_roots_with_workspace_roots(std::slice::from_ref(&cwd));
|
||||
let permission_profile = codex_protocol::models::PermissionProfile::from_runtime_permissions(
|
||||
&file_system_sandbox_policy,
|
||||
codex_protocol::protocol::NetworkSandboxPolicy::Restricted,
|
||||
);
|
||||
codex_sandboxing::EffectiveFilesystemPermissions::from_profile(
|
||||
&permission_profile,
|
||||
codex_sandboxing::FilesystemPermissionsContext {
|
||||
policy_evaluation_cwd: &cwd,
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("test filesystem policy should yield effective permissions: {err}")
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn create_filesystem_args(
|
||||
file_system_sandbox_policy: &codex_protocol::protocol::FileSystemSandboxPolicy,
|
||||
cwd: &Path,
|
||||
glob_scan_max_depth: Option<usize>,
|
||||
) -> Result<BwrapArgs> {
|
||||
let effective_filesystem_permissions =
|
||||
effective_test_filesystem_permissions(file_system_sandbox_policy, cwd);
|
||||
create_effective_filesystem_args(&effective_filesystem_permissions, cwd, glob_scan_max_depth)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn create_bwrap_command_args_for_policy(
|
||||
command: Vec<String>,
|
||||
file_system_sandbox_policy: &codex_protocol::protocol::FileSystemSandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
options: BwrapOptions,
|
||||
) -> Result<BwrapArgs> {
|
||||
let effective_filesystem_permissions =
|
||||
effective_test_filesystem_permissions(file_system_sandbox_policy, sandbox_policy_cwd);
|
||||
create_bwrap_command_args(
|
||||
command,
|
||||
&effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1360,7 +1385,7 @@ mod tests {
|
||||
#[test]
|
||||
fn full_disk_write_full_network_returns_unwrapped_command() {
|
||||
let command = vec!["/bin/true".to_string()];
|
||||
let args = create_bwrap_command_args(
|
||||
let args = create_bwrap_command_args_for_policy(
|
||||
command.clone(),
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
Path::new("/"),
|
||||
@@ -1379,7 +1404,7 @@ mod tests {
|
||||
#[test]
|
||||
fn full_disk_write_proxy_only_keeps_full_filesystem_but_unshares_network() {
|
||||
let command = vec!["/bin/true".to_string()];
|
||||
let args = create_bwrap_command_args(
|
||||
let args = create_bwrap_command_args_for_policy(
|
||||
command,
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
Path::new("/"),
|
||||
@@ -1431,7 +1456,7 @@ mod tests {
|
||||
]);
|
||||
let command = vec!["/bin/true".to_string()];
|
||||
|
||||
let args = create_bwrap_command_args(
|
||||
let args = create_bwrap_command_args_for_policy(
|
||||
command.clone(),
|
||||
&policy,
|
||||
temp_dir.path(),
|
||||
@@ -1479,7 +1504,7 @@ mod tests {
|
||||
},
|
||||
]);
|
||||
|
||||
let args = create_bwrap_command_args(
|
||||
let args = create_bwrap_command_args_for_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&policy,
|
||||
sandbox_policy_cwd.as_path(),
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
//! Filesystem restrictions are enforced by bubblewrap in `linux_run_main`.
|
||||
//! Landlock helpers remain available here as legacy/backup utilities.
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::Result;
|
||||
use codex_protocol::error::SandboxErr;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_sandboxing::EffectiveFilesystemPermissions;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
use landlock::ABI;
|
||||
@@ -39,15 +38,13 @@ use seccompiler::apply_filter;
|
||||
/// - installing the network seccomp filter when network access is disabled.
|
||||
///
|
||||
/// Filesystem restrictions are intentionally handled by bubblewrap.
|
||||
pub(crate) fn apply_permission_profile_to_current_thread(
|
||||
permission_profile: &PermissionProfile,
|
||||
cwd: &Path,
|
||||
pub(crate) fn apply_effective_permissions_to_current_thread(
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
apply_landlock_fs: bool,
|
||||
allow_network_for_proxy: bool,
|
||||
proxy_routed_network: bool,
|
||||
) -> Result<()> {
|
||||
let (file_system_sandbox_policy, network_sandbox_policy) =
|
||||
permission_profile.to_runtime_permissions();
|
||||
let network_seccomp_mode = network_seccomp_mode(
|
||||
network_sandbox_policy,
|
||||
allow_network_for_proxy,
|
||||
@@ -59,7 +56,7 @@ pub(crate) fn apply_permission_profile_to_current_thread(
|
||||
// we avoid this unless we need seccomp or we are explicitly using the
|
||||
// legacy Landlock filesystem pipeline.
|
||||
if network_seccomp_mode.is_some()
|
||||
|| (apply_landlock_fs && !file_system_sandbox_policy.has_full_disk_write_access())
|
||||
|| (apply_landlock_fs && !effective_filesystem_permissions.has_full_disk_write_access())
|
||||
{
|
||||
set_no_new_privs()?;
|
||||
}
|
||||
@@ -68,18 +65,18 @@ pub(crate) fn apply_permission_profile_to_current_thread(
|
||||
install_network_seccomp_filter_on_current_thread(mode)?;
|
||||
}
|
||||
|
||||
if apply_landlock_fs && !file_system_sandbox_policy.has_full_disk_write_access() {
|
||||
if !file_system_sandbox_policy.has_full_disk_read_access() {
|
||||
if apply_landlock_fs && !effective_filesystem_permissions.has_full_disk_write_access() {
|
||||
if !effective_filesystem_permissions.has_full_disk_read_access() {
|
||||
return Err(CodexErr::UnsupportedOperation(
|
||||
"Restricted read-only access is not supported by the legacy Linux Landlock filesystem backend."
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let writable_roots = file_system_sandbox_policy
|
||||
.get_writable_roots_with_cwd(cwd)
|
||||
.into_iter()
|
||||
.map(|writable_root| writable_root.root)
|
||||
let writable_roots = effective_filesystem_permissions
|
||||
.writable_roots
|
||||
.iter()
|
||||
.map(|writable_root| writable_root.root.clone())
|
||||
.collect();
|
||||
install_filesystem_landlock_rules_on_current_thread(writable_roots)?;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::time::Duration;
|
||||
use crate::bwrap::BwrapNetworkMode;
|
||||
use crate::bwrap::BwrapOptions;
|
||||
use crate::bwrap::create_bwrap_command_args;
|
||||
use crate::landlock::apply_permission_profile_to_current_thread;
|
||||
use crate::landlock::apply_effective_permissions_to_current_thread;
|
||||
use crate::launcher::exec_bwrap;
|
||||
use crate::launcher::preferred_bwrap_supports_argv0;
|
||||
use crate::proxy_routing::activate_proxy_routes_in_netns;
|
||||
@@ -29,7 +29,10 @@ use codex_protocol::error::Result as CodexResult;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::FileSystemSandboxPolicy;
|
||||
use codex_protocol::protocol::NetworkSandboxPolicy;
|
||||
use codex_sandboxing::EffectiveFilesystemPermissions;
|
||||
use codex_sandboxing::FilesystemPermissionsContext;
|
||||
use codex_sandboxing::landlock::CODEX_LINUX_SANDBOX_ARG0;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
static BWRAP_CHILD_PID: AtomicI32 = AtomicI32::new(0);
|
||||
static PENDING_FORWARDED_SIGNAL: AtomicI32 = AtomicI32::new(0);
|
||||
@@ -166,6 +169,15 @@ pub fn run_main() -> ! {
|
||||
file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
} = resolve_permission_profile(permission_profile).unwrap_or_else(|err| panic!("{err}"));
|
||||
let policy_evaluation_cwd = AbsolutePathBuf::from_absolute_path(&sandbox_policy_cwd)
|
||||
.unwrap_or_else(|err| panic!("sandbox policy cwd should be absolute: {err}"));
|
||||
let effective_filesystem_permissions = EffectiveFilesystemPermissions::from_profile(
|
||||
&permission_profile,
|
||||
FilesystemPermissionsContext {
|
||||
policy_evaluation_cwd: &policy_evaluation_cwd,
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|err| panic!("failed to derive effective filesystem permissions: {err}"));
|
||||
ensure_legacy_landlock_mode_supports_policy(
|
||||
use_legacy_landlock,
|
||||
&file_system_sandbox_policy,
|
||||
@@ -185,9 +197,9 @@ pub fn run_main() -> ! {
|
||||
}
|
||||
}
|
||||
let proxy_routing_active = allow_network_for_proxy;
|
||||
if let Err(e) = apply_permission_profile_to_current_thread(
|
||||
&permission_profile,
|
||||
&sandbox_policy_cwd,
|
||||
if let Err(e) = apply_effective_permissions_to_current_thread(
|
||||
&effective_filesystem_permissions,
|
||||
network_sandbox_policy,
|
||||
/*apply_landlock_fs*/ false,
|
||||
allow_network_for_proxy,
|
||||
proxy_routing_active,
|
||||
@@ -197,10 +209,10 @@ pub fn run_main() -> ! {
|
||||
exec_or_panic(command);
|
||||
}
|
||||
|
||||
if file_system_sandbox_policy.has_full_disk_write_access() && !allow_network_for_proxy {
|
||||
if let Err(e) = apply_permission_profile_to_current_thread(
|
||||
&permission_profile,
|
||||
&sandbox_policy_cwd,
|
||||
if effective_filesystem_permissions.has_full_disk_write_access() && !allow_network_for_proxy {
|
||||
if let Err(e) = apply_effective_permissions_to_current_thread(
|
||||
&effective_filesystem_permissions,
|
||||
network_sandbox_policy,
|
||||
/*apply_landlock_fs*/ false,
|
||||
allow_network_for_proxy,
|
||||
/*proxy_routed_network*/ false,
|
||||
@@ -233,7 +245,7 @@ pub fn run_main() -> ! {
|
||||
run_bwrap_with_proc_fallback(
|
||||
&sandbox_policy_cwd,
|
||||
command_cwd.as_deref(),
|
||||
&file_system_sandbox_policy,
|
||||
&effective_filesystem_permissions,
|
||||
network_sandbox_policy,
|
||||
inner,
|
||||
!no_proc,
|
||||
@@ -242,9 +254,9 @@ pub fn run_main() -> ! {
|
||||
}
|
||||
|
||||
// Legacy path: Landlock enforcement only, when bwrap sandboxing is not enabled.
|
||||
if let Err(e) = apply_permission_profile_to_current_thread(
|
||||
&permission_profile,
|
||||
&sandbox_policy_cwd,
|
||||
if let Err(e) = apply_effective_permissions_to_current_thread(
|
||||
&effective_filesystem_permissions,
|
||||
network_sandbox_policy,
|
||||
/*apply_landlock_fs*/ true,
|
||||
allow_network_for_proxy,
|
||||
/*proxy_routed_network*/ false,
|
||||
@@ -317,7 +329,7 @@ fn ensure_legacy_landlock_mode_supports_policy(
|
||||
fn run_bwrap_with_proc_fallback(
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: Option<&Path>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
inner: Vec<String>,
|
||||
mount_proc: bool,
|
||||
@@ -331,7 +343,7 @@ fn run_bwrap_with_proc_fallback(
|
||||
&& !preflight_proc_mount_support(
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
network_mode,
|
||||
)
|
||||
.unwrap_or_else(|err| exit_with_bwrap_build_error(err))
|
||||
@@ -348,7 +360,7 @@ fn run_bwrap_with_proc_fallback(
|
||||
};
|
||||
let mut bwrap_args = build_bwrap_argv(
|
||||
inner,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
options,
|
||||
@@ -373,14 +385,14 @@ fn bwrap_network_mode(
|
||||
|
||||
fn build_bwrap_argv(
|
||||
inner: Vec<String>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
options: BwrapOptions,
|
||||
) -> CodexResult<crate::bwrap::BwrapArgs> {
|
||||
let bwrap_args = create_bwrap_command_args(
|
||||
inner,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
options,
|
||||
@@ -444,13 +456,13 @@ fn current_process_argv0() -> String {
|
||||
fn preflight_proc_mount_support(
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
network_mode: BwrapNetworkMode,
|
||||
) -> CodexResult<bool> {
|
||||
let preflight_argv = build_preflight_bwrap_argv(
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
network_mode,
|
||||
)?;
|
||||
let stderr = run_bwrap_in_child_capture_stderr(preflight_argv);
|
||||
@@ -460,13 +472,13 @@ fn preflight_proc_mount_support(
|
||||
fn build_preflight_bwrap_argv(
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
effective_filesystem_permissions: &EffectiveFilesystemPermissions,
|
||||
network_mode: BwrapNetworkMode,
|
||||
) -> CodexResult<crate::bwrap::BwrapArgs> {
|
||||
let preflight_command = vec![resolve_true_command()];
|
||||
build_bwrap_argv(
|
||||
preflight_command,
|
||||
file_system_sandbox_policy,
|
||||
effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
BwrapOptions {
|
||||
|
||||
@@ -23,6 +23,64 @@ fn read_only_file_system_policy() -> FileSystemSandboxPolicy {
|
||||
read_only_permission_profile().file_system_sandbox_policy()
|
||||
}
|
||||
|
||||
fn effective_permissions_for_policy(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
cwd: &Path,
|
||||
) -> codex_sandboxing::EffectiveFilesystemPermissions {
|
||||
let cwd = AbsolutePathBuf::from_absolute_path(cwd)
|
||||
.unwrap_or_else(|err| panic!("test policy cwd should be absolute: {err}"));
|
||||
let file_system_sandbox_policy = file_system_sandbox_policy
|
||||
.clone()
|
||||
.materialize_project_roots_with_workspace_roots(std::slice::from_ref(&cwd));
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
);
|
||||
codex_sandboxing::EffectiveFilesystemPermissions::from_profile(
|
||||
&permission_profile,
|
||||
codex_sandboxing::FilesystemPermissionsContext {
|
||||
policy_evaluation_cwd: &cwd,
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("test filesystem policy should yield effective permissions: {err}")
|
||||
})
|
||||
}
|
||||
|
||||
fn build_bwrap_argv_for_policy(
|
||||
inner: Vec<String>,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
options: BwrapOptions,
|
||||
) -> codex_protocol::error::Result<crate::bwrap::BwrapArgs> {
|
||||
let effective_filesystem_permissions =
|
||||
effective_permissions_for_policy(file_system_sandbox_policy, sandbox_policy_cwd);
|
||||
build_bwrap_argv(
|
||||
inner,
|
||||
&effective_filesystem_permissions,
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_preflight_bwrap_argv_for_policy(
|
||||
sandbox_policy_cwd: &Path,
|
||||
command_cwd: &Path,
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
network_mode: BwrapNetworkMode,
|
||||
) -> codex_protocol::error::Result<crate::bwrap::BwrapArgs> {
|
||||
let effective_filesystem_permissions =
|
||||
effective_permissions_for_policy(file_system_sandbox_policy, sandbox_policy_cwd);
|
||||
build_preflight_bwrap_argv(
|
||||
sandbox_policy_cwd,
|
||||
command_cwd,
|
||||
&effective_filesystem_permissions,
|
||||
network_mode,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detects_proc_mount_invalid_argument_failure() {
|
||||
let stderr = "bwrap: Can't mount proc on /newroot/proc: Invalid argument";
|
||||
@@ -50,7 +108,7 @@ fn ignores_non_proc_mount_errors() {
|
||||
#[test]
|
||||
fn inserts_bwrap_argv0_before_command_separator() {
|
||||
let file_system_sandbox_policy = read_only_file_system_policy();
|
||||
let mut argv = build_bwrap_argv(
|
||||
let mut argv = build_bwrap_argv_for_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_sandbox_policy,
|
||||
Path::new("/"),
|
||||
@@ -94,7 +152,7 @@ fn inserts_bwrap_argv0_before_command_separator() {
|
||||
#[test]
|
||||
fn rewrites_inner_command_path_when_bwrap_lacks_argv0() {
|
||||
let file_system_sandbox_policy = read_only_file_system_policy();
|
||||
let mut argv = build_bwrap_argv(
|
||||
let mut argv = build_bwrap_argv_for_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_sandbox_policy,
|
||||
Path::new("/"),
|
||||
@@ -163,7 +221,7 @@ fn rewrites_bwrap_helper_command_not_nested_user_command_when_current_exe_appear
|
||||
#[test]
|
||||
fn inserts_unshare_net_when_network_isolation_requested() {
|
||||
let file_system_sandbox_policy = read_only_file_system_policy();
|
||||
let argv = build_bwrap_argv(
|
||||
let argv = build_bwrap_argv_for_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_sandbox_policy,
|
||||
Path::new("/"),
|
||||
@@ -182,7 +240,7 @@ fn inserts_unshare_net_when_network_isolation_requested() {
|
||||
#[test]
|
||||
fn inserts_unshare_net_when_proxy_only_network_mode_requested() {
|
||||
let file_system_sandbox_policy = read_only_file_system_policy();
|
||||
let argv = build_bwrap_argv(
|
||||
let argv = build_bwrap_argv_for_policy(
|
||||
vec!["/bin/true".to_string()],
|
||||
&file_system_sandbox_policy,
|
||||
Path::new("/"),
|
||||
@@ -263,7 +321,7 @@ fn managed_proxy_preflight_argv_is_wrapped_for_full_access_policy() {
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
/*allow_network_for_proxy*/ true,
|
||||
);
|
||||
let argv = build_preflight_bwrap_argv(
|
||||
let argv = build_preflight_bwrap_argv_for_policy(
|
||||
Path::new("/"),
|
||||
Path::new("/"),
|
||||
&FileSystemSandboxPolicy::unrestricted(),
|
||||
|
||||
Reference in New Issue
Block a user