Files
codex/codex-rs/core/src/landlock.rs
Michael Bolin e6db1a9442 linux-sandbox: switch helper plumbing to PermissionProfile (#20106)
## Why

`PermissionProfile` is the canonical runtime permission model in the
Rust workspace, but the Linux sandbox helper still accepted a legacy
`SandboxPolicy` plus separate filesystem and network policy flags. That
translation layer made the helper interface harder to reason about and
left `linux-sandbox`-specific callers and tests coupled to the legacy
policy representation.

This change moves the helper onto `PermissionProfile` directly so the
Linux sandbox plumbing matches the rest of the permission stack.

## What changed

- changed `codex-linux-sandbox` to accept `--permission-profile` and
derive the runtime filesystem and network policies internally
- updated the in-process seccomp and legacy Landlock path in
`codex-rs/linux-sandbox` to operate on `PermissionProfile`
- updated Linux sandbox argv construction in `codex-rs/sandboxing`,
`codex-rs/core`, and the CLI debug sandbox path to pass the canonical
profile instead of serializing compatibility policy projections
- simplified the Linux sandbox tests to build the exact permission
profile under test, including the managed-proxy path and
direct-runtime-enforcement carveout coverage
- removed helper-local `SandboxPolicy` usage from `bwrap` tests where
`FileSystemSandboxPolicy` is already the value being exercised

## Testing

- `cargo test -p codex-sandboxing`
- `cargo test -p codex-linux-sandbox` (on this macOS host, the crate
compiled cleanly and its Linux-only tests were cfg-gated)
- `cargo test -p codex-core --no-run`
- `cargo test -p codex-cli --no-run`
2026-04-28 19:43:44 -07:00

71 lines
2.6 KiB
Rust

use crate::spawn::SpawnChildRequest;
use crate::spawn::StdioPolicy;
use crate::spawn::spawn_child_async;
use codex_network_proxy::NetworkProxy;
use codex_protocol::models::PermissionProfile;
use codex_sandboxing::landlock::CODEX_LINUX_SANDBOX_ARG0;
use codex_sandboxing::landlock::allow_network_for_proxy;
use codex_sandboxing::landlock::create_linux_sandbox_command_args_for_permission_profile;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::collections::HashMap;
use std::path::Path;
use tokio::process::Child;
/// Spawn a shell tool command under the Linux sandbox helper
/// (codex-linux-sandbox), which defaults to bubblewrap for filesystem
/// isolation plus seccomp for network restrictions.
///
/// Unlike macOS Seatbelt where we directly embed the policy text, the Linux
/// helper is a separate executable. We pass the canonical permission profile
/// as JSON and let the helper derive the runtime filesystem/network policies.
#[allow(clippy::too_many_arguments)]
pub async fn spawn_command_under_linux_sandbox<P>(
codex_linux_sandbox_exe: P,
command: Vec<String>,
command_cwd: AbsolutePathBuf,
permission_profile: &PermissionProfile,
sandbox_policy_cwd: &AbsolutePathBuf,
use_legacy_landlock: bool,
stdio_policy: StdioPolicy,
network: Option<&NetworkProxy>,
env: HashMap<String, String>,
) -> std::io::Result<Child>
where
P: AsRef<Path>,
{
let network_sandbox_policy = permission_profile.network_sandbox_policy();
let args = create_linux_sandbox_command_args_for_permission_profile(
command,
command_cwd.as_path(),
permission_profile,
sandbox_policy_cwd,
use_legacy_landlock,
allow_network_for_proxy(/*enforce_managed_network*/ false),
);
let codex_linux_sandbox_exe = codex_linux_sandbox_exe.as_ref();
// Preserve the helper alias when we already have it; otherwise force argv0
// so arg0 dispatch still reaches the Linux sandbox path.
let arg0 = if codex_linux_sandbox_exe
.file_name()
.and_then(|name| name.to_str())
== Some(CODEX_LINUX_SANDBOX_ARG0)
{
// Old bubblewrap builds without `--argv0` need a real helper path whose
// basename still dispatches to the Linux sandbox entrypoint.
codex_linux_sandbox_exe.to_string_lossy().into_owned()
} else {
CODEX_LINUX_SANDBOX_ARG0.to_string()
};
spawn_child_async(SpawnChildRequest {
program: codex_linux_sandbox_exe.to_path_buf(),
args,
arg0: Some(&arg0),
cwd: command_cwd,
network_sandbox_policy,
network,
stdio_policy,
env,
})
.await
}