This is a major redesign of how sandbox configuration works and aims to fix https://github.com/openai/codex/issues/1248. Specifically, it replaces `sandbox_permissions` in `config.toml` (and the `-s`/`--sandbox-permission` CLI flags) with a "table" with effectively three variants: ```toml # Safest option: full disk is read-only, but writes and network access are disallowed. [sandbox] mode = "read-only" # The cwd of the Codex task is writable, as well as $TMPDIR on macOS. # writable_roots can be used to specify additional writable folders. [sandbox] mode = "workspace-write" writable_roots = [] # Optional, defaults to the empty list. network_access = false # Optional, defaults to false. # Disable sandboxing: use at your own risk!!! [sandbox] mode = "danger-full-access" ``` This should make sandboxing easier to reason about. While we have dropped support for `-s`, the way it works now is: - no flags => `read-only` - `--full-auto` => `workspace-write` - currently, there is no way to specify `danger-full-access` via a CLI flag, but we will revisit that as part of https://github.com/openai/codex/issues/1254 Outstanding issue: - As noted in the `TODO` on `SandboxPolicy::is_unrestricted()`, we are still conflating sandbox preferences with approval preferences in that case, which needs to be cleaned up.
55 lines
1.6 KiB
Rust
55 lines
1.6 KiB
Rust
use clap::Parser;
|
|
use std::ffi::CString;
|
|
use std::path::PathBuf;
|
|
|
|
use crate::landlock::apply_sandbox_policy_to_current_thread;
|
|
|
|
#[derive(Debug, Parser)]
|
|
pub struct LandlockCommand {
|
|
/// It is possible that the cwd used in the context of the sandbox policy
|
|
/// is different from the cwd of the process to spawn.
|
|
pub sandbox_policy_cwd: PathBuf,
|
|
|
|
pub sandbox_policy: codex_core::protocol::SandboxPolicy,
|
|
|
|
/// Full command args to run under landlock.
|
|
#[arg(trailing_var_arg = true)]
|
|
pub command: Vec<String>,
|
|
}
|
|
|
|
pub fn run_main() -> ! {
|
|
let LandlockCommand {
|
|
sandbox_policy_cwd,
|
|
sandbox_policy,
|
|
command,
|
|
} = LandlockCommand::parse();
|
|
|
|
if let Err(e) = apply_sandbox_policy_to_current_thread(&sandbox_policy, &sandbox_policy_cwd) {
|
|
panic!("error running landlock: {e:?}");
|
|
}
|
|
|
|
if command.is_empty() {
|
|
panic!("No command specified to execute.");
|
|
}
|
|
|
|
#[expect(clippy::expect_used)]
|
|
let c_command =
|
|
CString::new(command[0].as_str()).expect("Failed to convert command to CString");
|
|
#[expect(clippy::expect_used)]
|
|
let c_args: Vec<CString> = command
|
|
.iter()
|
|
.map(|arg| CString::new(arg.as_str()).expect("Failed to convert arg to CString"))
|
|
.collect();
|
|
|
|
let mut c_args_ptrs: Vec<*const libc::c_char> = c_args.iter().map(|arg| arg.as_ptr()).collect();
|
|
c_args_ptrs.push(std::ptr::null());
|
|
|
|
unsafe {
|
|
libc::execvp(c_command.as_ptr(), c_args_ptrs.as_ptr());
|
|
}
|
|
|
|
// If execvp returns, there was an error.
|
|
let err = std::io::Error::last_os_error();
|
|
panic!("Failed to execvp {}: {err}", command[0].as_str());
|
|
}
|