第 24 讲:Windows 沙箱双后端(受限令牌 + 专属账户)

Codex 源码解析 · 第 24 讲

Codex 源码解析系列 第 24 讲:Windows 沙箱双后端(受限令牌 + 专属账户) 基于 OpenAI Codex 源码 · 2026-10-17 💡 本讲一句话: Windows 没有 bwrap、没有 Landlock,Codex 就自己造了两套沙箱:legacy 后端用受限令牌+capability SID 把文件权限锁死在 ACL 上;elevated 后端直接创建两个专属本地账户(离线/在线),用 WFP 内核防火墙规则按账户封网。读完你能看懂 Windows 上"只读沙箱"和"workspace-write 沙箱"到底是怎么实现的。 一、为什么 Windows 需要两套后端 前几讲我们拆了 Linux 的 bwrap(第 22 讲)和 Landlock+Seatbelt 双引擎(第 23 讲)。到了 Windows,内核没有提供"给进程换一个文件系统视图"的原语——没有 mount namespace、没有 Landlock、没有 Seatbelt。Codex 的 codex-windows-sandbox crate(约 16K 行 Rust)只能站在两个更底层的原语上搭沙箱: 🔹 受限令牌(Restricted Token)+ capability SID :Windows ACL 是"白名单"模型——文件默认拒绝所有人,谁有 ACE 授权谁能访问。Codex 给每个可写根目录生成一个专属的 capability SID,只把这个 SID 写进该目录树的 ACL;进程拿到的受限令牌里只有这些 SID,于是"能写哪里"被精确锁死在文件系统层。 🔹 专属本地账户 + WFP/防火墙规则 :Windows 的防火墙和 WFP(Windows Filtering Platform)都支持"按用户 SID 匹配流量"。Codex 创建两个本地账户—— CodexSandboxOffline (离线,全网封禁只留 loopback 代理口)和 CodexSandboxOnline (在线),沙箱进程用哪个账户登录,网络策略就自动跟着走。 于是有了两个后端: legacy(Unelevated) ——当前用户自己跑受限令牌,不需要管理员; elevated ——需要 UAC 提权一次,创建专属账户、装 WFP 过滤器、配防火墙规则,之后每次启动沙箱都"登录"到这些账户上。源码入口在 core/src/windows_sandbox.rs (第 240-312 行): 📄 codex-rs/core/src/windows_sandbox.rs (第 239-312 行) pub enum WindowsSandboxSetupMode { // 两种后端模式:Elevated=提权专属账户,Unelevated=当前用户受限令牌 Elevated, // 需要 UAC 一次,之后每次沙箱都登录到 CodexSandboxOffline/Online 账户 Unelevated, // legacy 后端:不创建任何账户,纯靠受限令牌+ACL 隔离 } // 枚举本身没有方法——选择逻辑在 from_config/from_features 里按配置映射 pub async fn run_windows_sandbox_setup(request: WindowsSandboxSetupRequest) -> anyhow::Result<()> { // 统一入口:core 层调它来"准备沙箱环境" let start = Instant::now(); // 记录起点,后面算 setup 耗时打点 let mode = request.mode; // 取出后端模式(Elevated/Unelevated),决定走哪条分支 let originator_tag = sanitize_metric_tag_value(originator().value.as_str()); // 把调用来源清洗成合法 metric tag,便于按来源聚合失败率 let result = run_windows_sandbox_setup_and_persist(request).await; // 真正干活:setup + 持久化模式选…

阅读全文:Codex 源码解析 第 24 讲