mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Harden managed proxy setup for sandboxed executions (#34641)
## What changed - Make the generated Linux proxy socket directory readable inside restricted `bubblewrap` sandboxes so the proxy bridge can connect. - Route `WS_PROXY` and `WSS_PROXY` through the Linux managed proxy bridge. - Remove inherited proxy attribution tokens from unscoped executions while continuing to replace them with the current token for scoped executions. ## Testing - Exercise `WSS_PROXY` routing with a minimal filesystem policy. - Cover attribution-token removal and replacement during environment setup. GitOrigin-RevId: 2f14ddb26baab0147a786bc354d93eb5aad059f3
This commit is contained in:
@@ -167,7 +167,7 @@ pub fn run_main() -> ! {
|
||||
ensure_inner_stage_mode_is_valid(apply_seccomp_then_exec, use_legacy_landlock);
|
||||
let EffectivePermissions {
|
||||
permission_profile,
|
||||
file_system_sandbox_policy,
|
||||
mut file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
} = resolve_permission_profile(permission_profile).unwrap_or_else(|err| panic!("{err}"));
|
||||
ensure_legacy_landlock_mode_supports_policy(
|
||||
@@ -218,14 +218,17 @@ pub fn run_main() -> ! {
|
||||
// Outer stage: bubblewrap first, then re-enter this binary in the
|
||||
// sandboxed environment to apply seccomp. This path never falls back
|
||||
// to legacy Landlock on failure.
|
||||
let proxy_route_spec =
|
||||
if allow_network_for_proxy {
|
||||
Some(prepare_host_proxy_route_spec().unwrap_or_else(|err| {
|
||||
panic!("failed to prepare host proxy routing bridge: {err}")
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let proxy_route_spec = if allow_network_for_proxy {
|
||||
let (proxy_route_spec, socket_dir) = prepare_host_proxy_route_spec()
|
||||
.unwrap_or_else(|err| panic!("failed to prepare host proxy routing bridge: {err}"));
|
||||
file_system_sandbox_policy = file_system_sandbox_policy.with_additional_readable_roots(
|
||||
&sandbox_policy_cwd,
|
||||
std::slice::from_ref(&socket_dir),
|
||||
);
|
||||
Some(proxy_route_spec)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let inner = build_inner_seccomp_command(InnerSeccompCommandArgs {
|
||||
sandbox_policy_cwd: &sandbox_policy_cwd,
|
||||
command_cwd: command_cwd.as_deref(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use codex_network_proxy::PROXY_ATTRIBUTION_TOKEN_ENV_KEY;
|
||||
use codex_network_proxy::write_attribution_frame;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -29,6 +30,8 @@ use url::Url;
|
||||
const PROXY_ENV_KEYS: &[&str] = &[
|
||||
"HTTP_PROXY",
|
||||
"HTTPS_PROXY",
|
||||
"WS_PROXY",
|
||||
"WSS_PROXY",
|
||||
"ALL_PROXY",
|
||||
"FTP_PROXY",
|
||||
"YARN_HTTP_PROXY",
|
||||
@@ -72,7 +75,7 @@ struct ProxyRoutePlan {
|
||||
has_proxy_config: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_host_proxy_route_spec() -> io::Result<String> {
|
||||
pub(crate) fn prepare_host_proxy_route_spec() -> io::Result<(String, AbsolutePathBuf)> {
|
||||
let (attribution_token, plan) = extract_attribution_token_and_plan(std::env::vars().collect());
|
||||
// SAFETY: the sandbox helper is single-threaded here, before it forks bridge workers or
|
||||
// executes the user command.
|
||||
@@ -93,6 +96,7 @@ pub(crate) fn prepare_host_proxy_route_spec() -> io::Result<String> {
|
||||
let _ = cleanup_stale_proxy_socket_dirs_in(socket_parent_dir.as_path());
|
||||
|
||||
let socket_dir = create_proxy_socket_dir()?;
|
||||
let readable_socket_dir = AbsolutePathBuf::relative_to_current_dir(&socket_dir)?;
|
||||
let mut socket_by_endpoint: BTreeMap<SocketAddr, PathBuf> = BTreeMap::new();
|
||||
let mut next_index = 0usize;
|
||||
for route in &plan.routes {
|
||||
@@ -128,7 +132,8 @@ pub(crate) fn prepare_host_proxy_route_spec() -> io::Result<String> {
|
||||
});
|
||||
}
|
||||
|
||||
serde_json::to_string(&ProxyRouteSpec { routes }).map_err(io::Error::other)
|
||||
let spec = serde_json::to_string(&ProxyRouteSpec { routes }).map_err(io::Error::other)?;
|
||||
Ok((spec, readable_socket_dir))
|
||||
}
|
||||
|
||||
fn extract_attribution_token_and_plan(
|
||||
@@ -732,6 +737,8 @@ mod tests {
|
||||
fn recognizes_proxy_env_keys_case_insensitively() {
|
||||
assert_eq!(is_proxy_env_key("HTTP_PROXY"), true);
|
||||
assert_eq!(is_proxy_env_key("http_proxy"), true);
|
||||
assert_eq!(is_proxy_env_key("WS_PROXY"), true);
|
||||
assert_eq!(is_proxy_env_key("wss_proxy"), true);
|
||||
assert_eq!(is_proxy_env_key("PATH"), false);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user