Files
codex/codex-rs/mxc-sandbox/README.md
T
iceweasel-oai 23934d31b1 Skip read-only volume-root expansion in the MXC sandbox (#57985)
## Why

MXC read-only volume-root grants already provide recursive access, so enumerating their children is unnecessary.

## What changed

Expand only writable volume roots into grants for their immediate children. Document that read-only grants recurse, while new children created during a running command are not implicitly writable.

## Testing

Update policy tests to verify that only writable roots expand their children and that narrowing one volume preserves the other volume's grants.

GitOrigin-RevId: a7c7348b2f75bc7258fb1f130cfa4d9660e2faa6
2026-10-29 04:28:05 +00:00

125 lines
7.6 KiB
Markdown

# Native Windows MXC sandbox
This crate routes a command through the current Codex executable and directly
into Microsoft's MXC `BaseContainerRunner`. It requires a working Windows
process security environment (PSEC). It never invokes MXC's AppContainer
dispatcher, edits host ACLs, creates sandbox users, runs setup, or requests
elevation. The existing Codex Windows sandboxes remain separate backends.
Windows executors record `codex.windows_mxc.available` once per process with an
`available=true|false` tag. This measures runtime availability independently of
selection. Unsupported Windows executors reject MXC requests before execution.
`is_available()` uses MXC's cached create/close probe, rather than an OS build
number or the SDK's broad `platform_support()` result. The latter also reports
older AppContainer backends as supported. A requested deny path additionally
requires the native `PSE_SUPPORT_FS_DENY` capability; otherwise the command
fails before launch.
The wrapper inherits the command's pipes or ConPTY console. MXC creates its
child suspended, assigns a kill-on-close job before resuming it, and retains
the native policy through workload completion. Filesystem permissions come
from the canonical Codex permission profile, including protected metadata
carveouts. Supported managed network access allows IPv4 and IPv6 loopback
clients and servers, including the dedicated proxy listeners, while denying
direct non-loopback egress and general inbound network access.
Win32k calls and desktop handles remain available for PowerShell startup;
clipboard, input-injection, and desktop/system-control restrictions remain.
Filesystem conflicts in the emitted policy are enforced by BaseContainer:
equivalent path spellings and symlink/junction aliases use the strictest access
(`deny` > read-only > read-write), while more-specific paths override ancestor
grants. See the [BaseContainer path-precedence rules](https://github.com/microsoft/mxc/blob/main/docs/schema.md#overlapping-paths-for-windows-basecontainer).
Do not call MXC's shared `normalize_object_conflicts` before or after volume
expansion. Its identity preflight is used by mount-based backends and can reject
an otherwise usable Windows policy when a network share does not support
`FileIdInfo`, or a protected deny path cannot be opened for metadata. Codex sends
explicit path grants to BaseContainer without requiring that additional lookup.
We intentionally accept two limitations:
- Hard-link names retain independent path permissions. An allowed name can read
or modify the same file as a denied or read-only name; we do not tighten all
names to an object-wide restriction.
- Volume-root expansion uses each root's declared access without reconciling
aliases first. For example, a writable `V:\` plus a read-only junction to
`V:\` can produce a writable `V:\projects` grant. That generated, more-specific
grant permits writes through either name despite the read-only root alias.
## Selection and rollout
`windows.sandbox = "mxc"` is strict. The default-off `features.prefer_mxc`
selects MXC for local execution when available unless local binding is explicitly
forbidden; otherwise legacy configuration and setup apply. Remote executors keep
their configured backend. Command failures never trigger backend fallback.
Desktop can supply `-c features.prefer_mxc=true` from its saved rollout decision
on the next local Windows launch. Gate changes require a subsequent launch, and
rollback may require legacy setup. `config/read` retains the configured sandbox;
`windowsSandbox/readiness` reflects the effective local selection.
## Launch contract
`create_command_args()` wraps the command like the Seatbelt backend, using the
executor's Codex executable as the native SDK helper. It carries one typed
request: the canonical `PermissionProfile`, policy cwd, proxy context, and exact
argv. The helper inherits command cwd, environment, and stdio from the shared
process path; policy cwd can differ from command cwd.
Windows MXC reserves `SystemDrive` and `LOCALAPPDATA` for the host's validated,
nonempty values in both wrapper and explicit child environments. Caller
overrides are replaced case-insensitively; unavailable host values fail before
launch with a diagnostic naming the variable.
Windows may virtualize the child's `LOCALAPPDATA` into a sandbox directory
beneath the host profile.
The request uses launcher-only environment chunks to leave Windows' command-line
budget to the workload. Payloads are limited to 1,000,000 UTF-8 bytes and chunks
to 4096 bytes; the helper removes them before native process creation. Use
`codex sandbox windows` to debug through the same preparation path as execution.
## Limits and Windows validation
- Deny globs use the existing Windows sandbox resolver to expand matching files
and directories into concrete paths before launch. This has the same snapshot
semantics and scan limits as the existing Windows sandbox.
- Native deny paths depend on the host's capability probe. An installed Windows
update alone is not treated as evidence that every policy feature is enabled.
- When MXC is the executor's selected backend, managed networking defaults
`allow_local_binding` to `true`. An effective `false` after applying managed
requirements is a configuration error: native host-loopback access
is bidirectional, and MXC's proxy-peer identity mode is not integrated here.
`true` permits local servers and direct host-loopback connections and removes
the proxy's additional private-network destination checks. Proxy domain rules
still apply to proxied traffic; direct DNS remains denied. This default also
applies to remote Windows executors and does not enable disabled networking.
- Read-only volume-root grants recurse without enumerating children. Writable
volume-root grants do not recurse, so the adapter grants the root and its
immediate children; new children added during a running command are not
implicitly writable.
- Default read access excludes network shares unrelated to the policy or command
cwd. Explicit read/write grants remain supported. Unrelated shares are not
probed for object identity or enumerated for implicit reads.
- The native API represents paths and environment values as Unicode strings.
Non-Unicode values fail instead of undergoing lossy conversion.
- An empty child environment still uses the Windows user-profile defaults.
Supplying only two keys would turn it into an incomplete explicit environment,
so the wrapper's bootstrap values are removed before the SDK selects defaults.
Nonempty environments remain explicit except for these two host-owned values.
- The upstream runner terminates remaining descendants when the foreground
process exits, as well as on cancellation. Both existing Windows backends
preserve descendants after normal exit, so detached servers currently lose
that behavior under MXC. Retaining descendants safely requires a longer-lived
owner for the native policy and job.
- The command itself remains subject to Windows' command-line length limit.
- Portable tests validate policy translation and wrapper arguments. Actual
enforcement, nested access overrides, alternate path encodings, junctions
and hardlinks, protected metadata, ConPTY behavior, process-tree cancellation,
proxy isolation, and
comparison with the existing Windows and Unix sandboxes require the smoke
suite on supported Windows and the corresponding platform hosts.
Test the normal `powershell.exe` and `pwsh.exe` command paths, not only `cmd.exe`.
The MXC git revision is pinned with the workspace dependencies. Native launch
errors are returned without dumping the SDK's diagnostic buffer, which may
contain command or environment data.