Files
codex/codex-rs/windows-sandbox-rs/src/setup_runtime_bin.rs
T
iceweasel-oaiandGitHub 163eac9306 Grant sandbox users access to desktop runtime bin (#21564)
## Why

Codex desktop copies bundled Windows binaries out of `WindowsApps` into
a LocalAppData runtime cache before launching `codex.exe`. Sandboxed
commands can then need to execute helpers from that cache, but the
sandbox user group may not have read/execute access to the runtime bin
directory.

This makes the Windows sandbox refresh path repair that access directly
so the packaged desktop runtime remains usable from sandboxed sessions.

## What changed

- Added `setup_runtime_bin` to locate `%LOCALAPPDATA%\OpenAI\Codex\bin`,
matching the desktop bundled-binaries destination path, with the same
`USERPROFILE\AppData\Local` fallback shape.
- During refresh setup, check whether `CodexSandboxUsers` already has
read/execute access to the runtime bin directory.
- If access is missing, grant `CodexSandboxUsers` `OI/CI/RX` inheritance
on that directory.
- If the runtime bin directory does not exist, no-op cleanly.

## Verification

- `cargo build -p codex-windows-sandbox --bin
codex-windows-sandbox-setup`
- `cargo test -p codex-windows-sandbox --bin
codex-windows-sandbox-setup`
- Manual Windows ACL exercise against the installed packaged runtime
bin:
- existing inherited `CodexSandboxUsers:(I)(OI)(CI)(RX)` no-ops without
changing SDDL
- after disabling inheritance and removing the group ACE, setup adds
`CodexSandboxUsers:(OI)(CI)(RX)`
- with `LOCALAPPDATA` pointed at a fake location without
`OpenAI\Codex\bin`, setup exits successfully and does not create the
directory
- restored the real runtime bin with inherited ACLs and confirmed the
final SDDL matched the baseline exactly
2026-05-07 11:38:10 -07:00

93 lines
2.9 KiB
Rust

use std::ffi::c_void;
use std::fs::File;
use std::path::PathBuf;
use anyhow::Result;
use codex_windows_sandbox::ensure_allow_mask_aces_with_inheritance;
use codex_windows_sandbox::path_mask_allows;
use windows_sys::Win32::Security::CONTAINER_INHERIT_ACE;
use windows_sys::Win32::Security::OBJECT_INHERIT_ACE;
use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_EXECUTE;
use windows_sys::Win32::Storage::FileSystem::FILE_GENERIC_READ;
pub(super) fn ensure_codex_app_runtime_bin_readable(
sandbox_group_psid: *mut c_void,
refresh_errors: &mut Vec<String>,
log: &mut File,
) -> Result<()> {
let local_app_data = std::env::var_os("LOCALAPPDATA")
.map(PathBuf::from)
.or_else(|| {
std::env::var_os("USERPROFILE")
.map(PathBuf::from)
.map(|profile| profile.join("AppData").join("Local"))
});
let Some(local_app_data) = local_app_data else {
return Ok(());
};
// Codex desktop copies bundled Windows binaries out of WindowsApps to this
// fixed LocalAppData cache before launching codex.exe.
let runtime_bin_dir = local_app_data.join("OpenAI").join("Codex").join("bin");
if !runtime_bin_dir.is_dir() {
return Ok(());
}
let read_execute_mask = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE;
let has_access = match path_mask_allows(
&runtime_bin_dir,
&[sandbox_group_psid],
read_execute_mask,
/*require_all_bits*/ true,
) {
Ok(has_access) => has_access,
Err(err) => {
refresh_errors.push(format!(
"runtime bin read/execute mask check failed on {} for sandbox_group: {err}",
runtime_bin_dir.display()
));
super::log_line(
log,
&format!(
"runtime bin read/execute mask check failed on {} for sandbox_group: {err}; continuing",
runtime_bin_dir.display()
),
)?;
false
}
};
if has_access {
return Ok(());
}
super::log_line(
log,
&format!(
"granting read/execute ACE to {} for sandbox users",
runtime_bin_dir.display()
),
)?;
let result = unsafe {
ensure_allow_mask_aces_with_inheritance(
&runtime_bin_dir,
&[sandbox_group_psid],
read_execute_mask,
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
)
};
if let Err(err) = result {
refresh_errors.push(format!(
"grant read/execute ACE failed on {} for sandbox_group: {err}",
runtime_bin_dir.display()
));
super::log_line(
log,
&format!(
"grant read/execute ACE failed on {} for sandbox_group: {err}",
runtime_bin_dir.display()
),
)?;
}
Ok(())
}