Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codex-rs/cli/src/debug_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ async fn run_command_under_sandbox(
run_windows_sandbox_capture(
policy_str,
&sandbox_cwd,
base_dir.as_path(),
command_vec,
&cwd_clone,
env_map,
None,
Some(base_dir.as_path()),
)
})
.await;
Expand Down
8 changes: 6 additions & 2 deletions codex-rs/core/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,20 @@ async fn exec_windows_sandbox(
};

let sandbox_cwd = cwd.clone();
let logs_base_dir = find_codex_home().ok();
let codex_home = find_codex_home().map_err(|err| {
CodexErr::Io(io::Error::other(format!(
"windows sandbox: failed to resolve codex_home: {err}"
)))
})?;
let spawn_res = tokio::task::spawn_blocking(move || {
run_windows_sandbox_capture(
policy_str,
&sandbox_cwd,
codex_home.as_ref(),
command,
&cwd,
env,
timeout_ms,
logs_base_dir.as_deref(),
)
})
.await;
Expand Down
8 changes: 7 additions & 1 deletion codex-rs/windows-sandbox-rs/sandbox_smoketests.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,13 @@ def add(name: str, ok: bool, detail: str = ""):
add("WS: protected path case-variation denied", rc != 0 and assert_not_exists(git_variation), f"rc={rc}")

# 34. WS: policy tamper (.codex artifacts) denied
rc, out, err = run_sbx("workspace-write", ["cmd", "/c", "echo tamper > .codex\\cap_sid"], WS_ROOT)
codex_home = Path(os.environ["USERPROFILE"]) / ".codex"
cap_sid_target = codex_home / "cap_sid"
rc, out, err = run_sbx(
"workspace-write",
["cmd", "/c", f"echo tamper > \"{cap_sid_target}\""],
WS_ROOT,
Comment thread
iceweasel-oai marked this conversation as resolved.
)
rc2, out2, err2 = run_sbx("workspace-write", ["cmd", "/c", "echo tamper > .codex\\policy.json"], WS_ROOT)
add("WS: .codex cap_sid tamper denied", rc != 0, f"rc={rc}, err={err}")
add("WS: .codex policy tamper denied", rc2 != 0, f"rc={rc2}, err={err2}")
Expand Down
8 changes: 4 additions & 4 deletions codex-rs/windows-sandbox-rs/src/cap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub struct CapSids {
pub readonly: String,
}

pub fn cap_sid_file(policy_cwd: &Path) -> PathBuf {
policy_cwd.join(".codex").join("cap_sid")
pub fn cap_sid_file(codex_home: &Path) -> PathBuf {
codex_home.join("cap_sid")
}

fn make_random_cap_sid_string() -> String {
Expand All @@ -26,8 +26,8 @@ fn make_random_cap_sid_string() -> String {
format!("S-1-5-21-{}-{}-{}-{}", a, b, c, d)
}

pub fn load_or_create_cap_sids(policy_cwd: &Path) -> CapSids {
let path = cap_sid_file(policy_cwd);
pub fn load_or_create_cap_sids(codex_home: &Path) -> CapSids {
let path = cap_sid_file(codex_home);
if path.exists() {
if let Ok(txt) = fs::read_to_string(&path) {
let t = txt.trim();
Expand Down
30 changes: 16 additions & 14 deletions codex-rs/windows-sandbox-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ mod windows_impl {
Ok(())
}

fn ensure_codex_home_exists(p: &Path) -> Result<()> {
std::fs::create_dir_all(p)?;
Ok(())
}

fn make_env_block(env: &HashMap<String, String>) -> Vec<u16> {
let mut items: Vec<(String, String)> =
env.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
Expand Down Expand Up @@ -179,40 +184,37 @@ mod windows_impl {
pub fn run_windows_sandbox_capture(
policy_json_or_preset: &str,
sandbox_policy_cwd: &Path,
codex_home: &Path,
command: Vec<String>,
cwd: &Path,
mut env_map: HashMap<String, String>,
timeout_ms: Option<u64>,
logs_base_dir: Option<&Path>,
) -> Result<CaptureResult> {
let policy = SandboxPolicy::parse(policy_json_or_preset)?;
normalize_null_device_env(&mut env_map);
ensure_non_interactive_pager(&mut env_map);
apply_no_network_to_env(&mut env_map)?;
ensure_codex_home_exists(codex_home)?;

let current_dir = cwd.to_path_buf();
// for now, don't fail if we detect world-writable directories
// audit::audit_everyone_writable(&current_dir, &env_map)?;
let logs_base_dir = Some(codex_home);
log_start(&command, logs_base_dir);
let cap_sid_path = cap_sid_file(codex_home);
let (h_token, psid_to_use): (HANDLE, *mut c_void) = unsafe {
match &policy.0 {
SandboxMode::ReadOnly => {
let caps = load_or_create_cap_sids(sandbox_policy_cwd);
ensure_dir(&cap_sid_file(sandbox_policy_cwd))?;
fs::write(
cap_sid_file(sandbox_policy_cwd),
serde_json::to_string(&caps)?,
)?;
let caps = load_or_create_cap_sids(codex_home);
ensure_dir(&cap_sid_path)?;
fs::write(&cap_sid_path, serde_json::to_string(&caps)?)?;
let psid = convert_string_sid_to_sid(&caps.readonly).unwrap();
super::token::create_readonly_token_with_cap(psid)?
}
SandboxMode::WorkspaceWrite => {
let caps = load_or_create_cap_sids(sandbox_policy_cwd);
ensure_dir(&cap_sid_file(sandbox_policy_cwd))?;
fs::write(
cap_sid_file(sandbox_policy_cwd),
serde_json::to_string(&caps)?,
)?;
let caps = load_or_create_cap_sids(codex_home);
ensure_dir(&cap_sid_path)?;
fs::write(&cap_sid_path, serde_json::to_string(&caps)?)?;
let psid = convert_string_sid_to_sid(&caps.workspace).unwrap();
super::token::create_workspace_write_token_with_cap(psid)?
}
Expand Down Expand Up @@ -445,11 +447,11 @@ mod stub {
pub fn run_windows_sandbox_capture(
_policy_json_or_preset: &str,
_sandbox_policy_cwd: &Path,
_codex_home: &Path,
_command: Vec<String>,
_cwd: &Path,
_env_map: HashMap<String, String>,
_timeout_ms: Option<u64>,
_logs_base_dir: Option<&Path>,
) -> Result<CaptureResult> {
bail!("Windows sandbox is only available on Windows")
}
Expand Down
Loading