mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
Block WSL interop escapes from restricted filesystem sandboxes (#44286)
## Why With network access enabled, WSL interop can launch Windows processes outside the Linux filesystem sandbox, including using `wsl.exe` to reenter the distribution as root. ## What changed - Mask WSL interop sockets in bubblewrap when filesystem write access is restricted, and hide inherited procfs when running without a fresh proc mount. - Deny `AF_VSOCK` sockets and `io_uring` under restricted filesystem policies even when ordinary network access is allowed, closing the VM socket route to host services. - Reject legacy Landlock configurations that combine restricted filesystem access with unrestricted networking when the WSL interop directory exists. ## Testing Add unit coverage for mount masking and legacy policy rejection, plus WSL integration tests for Windows process launch, bind aliases, direct `/init` invocation, root reentry, and `--no-proc` isolation. WSL tests skip when host prerequisites are unavailable. GitOrigin-RevId: 1e8b97ac43675807ee541ca614534d9b1febf410
This commit is contained in:
@@ -55,6 +55,7 @@ const LINUX_PLATFORM_DEFAULT_READ_ROOTS: &[&str] = &[
|
||||
];
|
||||
|
||||
const MAX_UNREADABLE_GLOB_MATCHES: usize = 8192;
|
||||
pub(crate) const WSL_INTEROP_DIR: &str = "/run/WSL";
|
||||
|
||||
/// Options that control how bubblewrap is invoked.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -66,6 +67,8 @@ pub(crate) struct BwrapOptions {
|
||||
pub mount_proc: bool,
|
||||
/// How networking should be configured inside the bubblewrap sandbox.
|
||||
pub network_mode: BwrapNetworkMode,
|
||||
/// Hide the WSL Windows interop socket from commands with restricted filesystem access.
|
||||
pub mask_wsl_interop: bool,
|
||||
/// Optional maximum depth for expanding unreadable glob patterns with ripgrep.
|
||||
///
|
||||
/// Keep this uncapped by default so existing nested deny-read matches are
|
||||
@@ -78,6 +81,7 @@ impl Default for BwrapOptions {
|
||||
Self {
|
||||
mount_proc: true,
|
||||
network_mode: BwrapNetworkMode::FullAccess,
|
||||
mask_wsl_interop: false,
|
||||
glob_scan_max_depth: None,
|
||||
}
|
||||
}
|
||||
@@ -329,6 +333,19 @@ fn create_bwrap_flags(
|
||||
args.push("--new-session".to_string());
|
||||
args.push("--die-with-parent".to_string());
|
||||
args.extend(filesystem_args);
|
||||
if options.mask_wsl_interop {
|
||||
// WSL's Windows-process bridge uses Unix sockets under /run/WSL.
|
||||
// Mask them after all filesystem binds so network access cannot bypass
|
||||
// the Linux filesystem policy by launching an unrestricted Windows process.
|
||||
args.push("--tmpfs".to_string());
|
||||
args.push(WSL_INTEROP_DIR.to_string());
|
||||
if !options.mount_proc {
|
||||
// Without a fresh procfs, the root bind retains the host procfs.
|
||||
// Hide it so /proc/<host-pid>/root cannot alias the interop sockets.
|
||||
args.push("--tmpfs".to_string());
|
||||
args.push("/proc".to_string());
|
||||
}
|
||||
}
|
||||
// Request a user namespace explicitly rather than relying on bubblewrap's
|
||||
// auto-enable behavior, which is skipped when the caller runs as uid 0.
|
||||
args.push("--unshare-user".to_string());
|
||||
|
||||
Reference in New Issue
Block a user