发布

  • fix: overhaul how we spawn commands under seccomp/landlock on Linux (#1086)

    frostbyte_neo 发布于 2025-05-23 18:37:07 +00:00

    Historically, we spawned the Seatbelt and Landlock sandboxes in
    substantially different ways:

    For Seatbelt, we would run /usr/bin/sandbox-exec with our policy
    specified as an arg followed by the original command:

    https://github.com/openai/codex/blob/142e1d1667acb22f24c3fd7593bec40cd76034e2/codex-rs/core/src/exec.rs#L147-L219

    For Landlock/Seccomp, we would do
    tokio::runtime::Builder::new_current_thread(), invoke
    Landlock/Seccomp APIs to modify the permissions of that new thread
    , and
    then spawn the command:

    https://github.com/openai/codex/blob/142e1d1667acb22f24c3fd7593bec40cd76034e2/codex-rs/core/src/exec_linux.rs#L28-L49

    While it is neat that Landlock/Seccomp supports applying a policy to
    only one thread without having to apply it to the entire process, it
    requires us to maintain two different codepaths and is a bit harder to
    reason about. The tipping point was
    https://github.com/openai/codex/pull/1061, in which we had to start
    building up the env in an unexpected way for the existing
    Landlock/Seccomp approach to continue to work.

    This PR overhauls things so that we do similar things for Mac and Linux.
    It turned out that we were already building our own "helper binary"
    comparable to Mac's sandbox-exec as part of the cli crate:

    https://github.com/openai/codex/blob/142e1d1667acb22f24c3fd7593bec40cd76034e2/codex-rs/cli/Cargo.toml#L10-L12

    We originally created this to build a small binary to include with the
    Node.js version of the Codex CLI to provide support for Linux
    sandboxing.

    Though the sticky bit is that, at this point, we still want to deploy
    the Rust version of Codex as a single, standalone binary rather than a
    CLI and a supporting sandboxing binary. To satisfy this goal, we use
    "the arg0 trick," in which we:

    • use std::env::current_exe() to get the path to the CLI that is
      currently running
    • use the CLI as the program for the Command
    • set "codex-linux-sandbox" as arg0 for the Command

    A CLI that supports sandboxing should check arg0 at the start of the
    program. If it is "codex-linux-sandbox", it must invoke
    codex_linux_sandbox::run_main(), which runs the CLI as if it were
    codex-linux-sandbox. When acting as codex-linux-sandbox, we make the
    appropriate Landlock/Seccomp API calls and then use execvp(3) to spawn
    the original command, so do replace the process rather than spawn a
    subprocess. Incidentally, we do this before starting the Tokio runtime,
    so the process should only have one thread when execvp(3) is called.

    Because the core crate that needs to spawn the Linux sandboxing is not
    a CLI in its own right, this means that every CLI that includes core
    and relies on this behavior has to (1) implement it and (2) provide the
    path to the sandboxing executable. While the path is almost always
    std::env::current_exe(), we needed to make this configurable for
    integration tests, so Config now has a codex_linux_sandbox_exe: Option<PathBuf> property to facilitate threading this through,
    introduced in https://github.com/openai/codex/pull/1089.

    This common pattern is now captured in
    codex_linux_sandbox::run_with_sandbox() and all of the main.rs
    functions that should use it have been updated as part of this PR.

    The codex-linux-sandbox crate added to the Cargo workspace as part of
    this PR now has the bulk of the Landlock/Seccomp logic, which makes
    core a bit simpler. Indeed, core/src/exec_linux.rs and
    core/src/landlock.rs were removed/ported as part of this PR. I also
    moved the unit tests for this code into an integration test,
    linux-sandbox/tests/landlock.rs, in which I use
    env!("CARGO_BIN_EXE_codex-linux-sandbox") as the value for
    codex_linux_sandbox_exe since std::env::current_exe() is not
    appropriate in that case.

    下载附件