-
fix: overhaul how we spawn commands under seccomp/landlock on Linux (#1086)
发布于
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-execwith our policy
specified as an arg followed by the original command: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: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 theenvin 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'ssandbox-execas part of theclicrate: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
programfor theCommand - set
"codex-linux-sandbox"as arg0 for theCommand
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 ascodex-linux-sandbox, we make the
appropriate Landlock/Seccomp API calls and then useexecvp(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 whenexecvp(3)is called.Because the
corecrate that needs to spawn the Linux sandboxing is not
a CLI in its own right, this means that every CLI that includescore
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, soConfignow has acodex_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 themain.rs
functions that should use it have been updated as part of this PR.The
codex-linux-sandboxcrate added to the Cargo workspace as part of
this PR now has the bulk of the Landlock/Seccomp logic, which makes
corea bit simpler. Indeed,core/src/exec_linux.rsand
core/src/landlock.rswere 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_exesincestd::env::current_exe()is not
appropriate in that case.下载附件
- use