Skip to content

クロスプラットフォームサンドボックス (Sandbox)

源码版本rust-v0.145.0

codex はコマンド実行をプラットフォームネイティブの sandbox に隔離する:macOS は sandbox-exec (seatbelt)、Linux は bubblewrap + seccomp、Windows は restricted token。sandboxing crate が統一抽象を提供し、linux-sandbox/bwrap/windows-sandbox-rs/process-hardening/ が各プラットフォームの実装だ。core は各 exec の前に SandboxType を算出し、SandboxManager::transform に渡して実際に spawn する argv を組み立てる。

責務

  1. PermissionProfile に従い sandbox を有効にするか、どの backend を使うかを決める:codex-rs/sandboxing/src/manager.rs:273-319
  2. macOS で sandbox-exec の seatbelt policy と argv を組み立てる:codex-rs/sandboxing/src/seatbelt.rs:21-30
  3. Linux で codex-linux-sandbox helper を使う:まず no_new_privs + seccomp を設定し、その後 bubblewrap を exec する:codex-rs/linux-sandbox/src/lib.rs:1-30
  4. Windows で restricted token / elevated backend によりファイルシステムとネットワークを隔離する:codex-rs/windows-sandbox-rs/src/lib.rs:13-50
  5. main の前にプロセスレベルの hardening(core dump 無効化、ptrace 拒否、LD_PRELOAD/DYLD_* のクリア)を行う:codex-rs/process-hardening/src/lib.rs:12-25

設計動機

なぜ execpolicy のブロックをそのまま信じないのか?モデルは任意の shell を構築でき、ルールエンジンには常に境界 case があるからだ。各コマンドを OS ネイティブの sandbox に強制的に閉じ込めるのは、「モデルがどう回避してもカーネル層で止める」最後の砦だ。SandboxablePreference::Auto は workspace-write / read-only などのポリシープロファイルで sandbox を有効にし、full-access プロファイルは SandboxType::None に退化し、無駄なプロセス包装を避ける。

各プラットフォームの backend が異なるのは、クロスプラットフォームで統一された sandbox プリミティブが存在しないからだ:macOS の seatbelt は宣言型 .sbpl、Linux の bubblewrap は user namespace + bind mount、Windows の restricted token は token + ACL。SandboxType enum がこの三つの backend と None を同じラベルに統一し、core/exec-server はラベルだけを見てプラットフォーム詳細を気にしない。

主要ファイル

SandboxType は三つのプラットフォーム backend と「sandbox なし」を一つのラベルに統一し、core はラベルだけを見る。

rust
pub enum SandboxType {
    None,
    MacosSeatbelt,
    LinuxSeccomp,
    WindowsRestrictedToken,
}

select_initial では、まず should_sandbox で sandbox が必要かを決め、その後にプラットフォームがどの backend を提供できるかを問う:

rust
pub fn select_initial(
    &self,
    file_system_policy: &FileSystemSandboxPolicy,
    network_policy: NetworkSandboxPolicy,
    pref: SandboxablePreference,
    windows_sandbox_level: WindowsSandboxLevel,
    has_managed_network_requirements: bool,
) -> SandboxType {
    if self.should_sandbox(
        file_system_policy,
        network_policy,
        pref,
        has_managed_network_requirements,
    ) {
        get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled)
            .unwrap_or(SandboxType::None)
    } else {
        SandboxType::None
    }
}

Linux launcher はシステム bwrap と bundled bwrap のどちらかを選び、見つからなければ panic する——bubblewrap が使えないと Linux sandbox のリンク全体が切れる。

rust
pub(crate) fn exec_bwrap(argv: Vec<String>, preserved_files: Vec<File>) -> ! {
    match preferred_bwrap_launcher() {
        BubblewrapLauncher::System(launcher) => {
            exec_system_bwrap(&launcher.program, argv, preserved_files)
        }
        BubblewrapLauncher::Bundled(launcher) => launcher.exec(argv, preserved_files),
        BubblewrapLauncher::Unavailable => {
            panic!(
                "bubblewrap is unavailable: no system bwrap was found on PATH and no bundled \
                 codex-resources/bwrap binary was found next to the Codex executable"
            )
        }
    }
}

データフロー

境界と失敗

まとめ

SandboxManager は codex のクロスプラットフォーム sandbox の統一入口で、PermissionProfileSandboxType に翻訳し、さらに wrapper 付き argv に翻訳する。プラットフォーム backend はそれぞれ独立に隔離するが、すべて同じ FileSystemSandboxPolicy / NetworkSandboxPolicy から導出する。「なぜこのコマンドが拒否されたか」の現場を追うには コマンド分類 execpolicyコマンド実行 exec-server の二ページを参照。