mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
Avoid UAC bootstrap for unelevated Windows sandbox
This commit is contained in:
@@ -121,6 +121,14 @@ fn windows_sandbox_uses_elevated_backend(
|
||||
proxy_enforced || matches!(sandbox_level, WindowsSandboxLevel::Elevated)
|
||||
}
|
||||
|
||||
fn windows_sandbox_allows_setup_bootstrap(
|
||||
sandbox_level: WindowsSandboxLevel,
|
||||
proxy_enforced: bool,
|
||||
) -> bool {
|
||||
matches!(sandbox_level, WindowsSandboxLevel::Elevated)
|
||||
|| !windows_sandbox_uses_elevated_backend(sandbox_level, proxy_enforced)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum ExecCapturePolicy {
|
||||
/// Shell-like execs keep the historical output cap and timeout behavior.
|
||||
@@ -604,6 +612,8 @@ async fn exec_windows_sandbox(
|
||||
let sandbox_level = windows_sandbox_level;
|
||||
let proxy_enforced = network.is_some();
|
||||
let use_elevated = windows_sandbox_uses_elevated_backend(sandbox_level, proxy_enforced);
|
||||
let allow_setup_bootstrap =
|
||||
windows_sandbox_allows_setup_bootstrap(sandbox_level, proxy_enforced);
|
||||
let additional_deny_write_paths = windows_sandbox_filesystem_overrides
|
||||
.map(|overrides| {
|
||||
overrides
|
||||
@@ -641,6 +651,7 @@ async fn exec_windows_sandbox(
|
||||
timeout_ms,
|
||||
use_private_desktop: windows_sandbox_private_desktop,
|
||||
proxy_enforced,
|
||||
allow_setup_bootstrap,
|
||||
read_roots_override: elevated_read_roots_override.as_deref(),
|
||||
read_roots_include_platform_defaults:
|
||||
elevated_read_roots_include_platform_defaults,
|
||||
|
||||
@@ -425,6 +425,22 @@ fn windows_proxy_enforcement_uses_elevated_backend() {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_proxy_enforcement_only_bootstraps_setup_for_explicit_elevated_mode() {
|
||||
assert!(windows_sandbox_allows_setup_bootstrap(
|
||||
WindowsSandboxLevel::RestrictedToken,
|
||||
/*proxy_enforced*/ false,
|
||||
));
|
||||
assert!(!windows_sandbox_allows_setup_bootstrap(
|
||||
WindowsSandboxLevel::RestrictedToken,
|
||||
/*proxy_enforced*/ true,
|
||||
));
|
||||
assert!(windows_sandbox_allows_setup_bootstrap(
|
||||
WindowsSandboxLevel::Elevated,
|
||||
/*proxy_enforced*/ false,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_restricted_token_rejects_network_only_restrictions() {
|
||||
let policy = SandboxPolicy::ExternalSandbox {
|
||||
|
||||
@@ -12,6 +12,7 @@ pub struct ElevatedSandboxCaptureRequest<'a> {
|
||||
pub timeout_ms: Option<u64>,
|
||||
pub use_private_desktop: bool,
|
||||
pub proxy_enforced: bool,
|
||||
pub allow_setup_bootstrap: bool,
|
||||
pub read_roots_override: Option<&'a [PathBuf]>,
|
||||
pub read_roots_include_platform_defaults: bool,
|
||||
pub write_roots_override: Option<&'a [PathBuf]>,
|
||||
@@ -121,6 +122,7 @@ mod windows_impl {
|
||||
timeout_ms,
|
||||
use_private_desktop,
|
||||
proxy_enforced,
|
||||
allow_setup_bootstrap,
|
||||
read_roots_override,
|
||||
read_roots_include_platform_defaults,
|
||||
write_roots_override,
|
||||
@@ -148,6 +150,7 @@ mod windows_impl {
|
||||
write_roots_override,
|
||||
deny_write_paths_override,
|
||||
proxy_enforced,
|
||||
allow_setup_bootstrap,
|
||||
)?;
|
||||
// Build capability SID for ACL grants.
|
||||
if matches!(
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use crate::dpapi;
|
||||
use crate::logging::debug_log;
|
||||
use crate::policy::SandboxPolicy;
|
||||
use crate::setup::SandboxNetworkIdentity;
|
||||
use crate::setup::SandboxUserRecord;
|
||||
use crate::setup::SandboxUsersFile;
|
||||
use crate::setup::SetupMarker;
|
||||
use crate::setup::gather_read_roots;
|
||||
use crate::setup::gather_write_roots;
|
||||
use crate::setup::offline_proxy_settings_from_env;
|
||||
@@ -8,15 +12,11 @@ use crate::setup::run_elevated_setup;
|
||||
use crate::setup::run_setup_refresh_with_overrides;
|
||||
use crate::setup::sandbox_users_path;
|
||||
use crate::setup::setup_marker_path;
|
||||
use crate::setup::SandboxNetworkIdentity;
|
||||
use crate::setup::SandboxUserRecord;
|
||||
use crate::setup::SandboxUsersFile;
|
||||
use crate::setup::SetupMarker;
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
||||
use anyhow::anyhow;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
@@ -141,6 +141,7 @@ pub fn require_logon_sandbox_creds(
|
||||
write_roots_override: Option<&[PathBuf]>,
|
||||
deny_write_paths_override: &[PathBuf],
|
||||
proxy_enforced: bool,
|
||||
allow_setup_bootstrap: bool,
|
||||
) -> Result<SandboxCreds> {
|
||||
let sandbox_dir = crate::setup::sandbox_dir(codex_home);
|
||||
let needed_read = read_roots_override
|
||||
@@ -150,8 +151,7 @@ pub fn require_logon_sandbox_creds(
|
||||
.map(<[PathBuf]>::to_vec)
|
||||
.unwrap_or_else(|| gather_write_roots(policy, policy_cwd, command_cwd, env_map));
|
||||
let network_identity = SandboxNetworkIdentity::from_policy(policy, proxy_enforced);
|
||||
let desired_offline_proxy_settings =
|
||||
offline_proxy_settings_from_env(env_map, network_identity);
|
||||
let desired_offline_proxy_settings = offline_proxy_settings_from_env(env_map, network_identity);
|
||||
// NOTE: Do not add CODEX_HOME/.sandbox to `needed_write`; it must remain non-writable by the
|
||||
// restricted capability token. The setup helper's `lock_sandbox_dir` is responsible for
|
||||
// granting the sandbox group access to this directory without granting the capability SID.
|
||||
@@ -167,8 +167,9 @@ pub fn require_logon_sandbox_creds(
|
||||
} else {
|
||||
let selected = select_identity(network_identity, codex_home)?;
|
||||
if selected.is_none() {
|
||||
setup_reason =
|
||||
Some("sandbox users missing or incompatible with marker version".to_string());
|
||||
setup_reason = Some(
|
||||
"sandbox users missing or incompatible with marker version".to_string(),
|
||||
);
|
||||
}
|
||||
selected
|
||||
}
|
||||
@@ -188,6 +189,11 @@ pub fn require_logon_sandbox_creds(
|
||||
} else {
|
||||
crate::logging::log_note("sandbox setup required", Some(&sandbox_dir));
|
||||
}
|
||||
if !allow_setup_bootstrap {
|
||||
return Err(anyhow!(
|
||||
"windows unelevated sandbox cannot auto-run elevated setup to enforce restricted network access; rerun Windows sandbox setup in elevated mode or enable network access"
|
||||
));
|
||||
}
|
||||
run_elevated_setup(
|
||||
crate::setup::SandboxSetupRequest {
|
||||
policy,
|
||||
|
||||
@@ -299,6 +299,7 @@ pub(crate) fn prepare_elevated_spawn_context(
|
||||
write_roots_override,
|
||||
&deny_write_paths,
|
||||
/*proxy_enforced*/ false,
|
||||
/*allow_setup_bootstrap*/ true,
|
||||
)?;
|
||||
let caps = load_or_create_cap_sids(codex_home)?;
|
||||
let (psid_to_use, cap_sids) = match &common.policy {
|
||||
|
||||
Reference in New Issue
Block a user