Allow host runtimes to bypass the native builder sandbox

This commit is contained in:
2026-11-12 09:32:30 +00:00
parent 0b79bb4227
commit a0bb71b175
11 changed files with 197 additions and 84 deletions
+64 -44
View File
@@ -47,15 +47,23 @@ pub struct Builder {
root: Arc<dyn Layer>,
directory: PathBuf,
lock: Mutex<()>,
no_sandbox: bool,
}
impl Builder {
pub fn new(root: Arc<dyn Layer>, host: &Path) -> Result<Self> {
Self::new_with_options(root, host, false)
}
pub fn new_with_options(root: Arc<dyn Layer>, host: &Path, no_sandbox: bool) -> Result<Self> {
Ok(Self {
root,
directory: std::fs::canonicalize(host)?.join("builds"),
lock: Mutex::new(()),
no_sandbox,
})
}
fn command(&self) -> Command {
Command::new(if self.no_sandbox { "cargo" } else { "bwrap" })
}
pub async fn execute(&self, request: Request, tx: &mpsc::Sender<Event>) -> Result<()> {
let _guard = self.lock.lock().await;
let action = request
@@ -221,60 +229,72 @@ impl Builder {
if action == "run" && run_path.exists() {
std::fs::remove_file(&run_path)?;
}
let mut cmd = Command::new("bwrap");
cmd.args([
"--unshare-user",
"--unshare-pid",
"--unshare-net",
"--die-with-parent",
"--ro-bind",
"/nix/store",
"/nix/store",
])
.arg("--bind")
.arg(&temporary)
.arg("/tmp")
.arg("--ro-bind")
.arg(executable("sh")?)
.arg("/bin/sh");
for path in [&source, &target_mount, &cache] {
cmd.arg("--bind").arg(path).arg(path);
let mut cmd = self.command();
if !self.no_sandbox {
cmd.args([
"--unshare-user",
"--unshare-pid",
"--unshare-net",
"--die-with-parent",
"--ro-bind",
"/nix/store",
"/nix/store",
])
.arg("--bind")
.arg(&temporary)
.arg("/tmp")
.arg("--ro-bind")
.arg(executable("sh")?)
.arg("/bin/sh");
for path in [&source, &target_mount, &cache] {
cmd.arg("--bind").arg(path).arg(path);
}
for path in [&registry, &tools] {
cmd.arg("--ro-bind").arg(path).arg(path);
}
cmd.args([
"--proc",
"/proc",
"--dev",
"/dev",
"--remount-ro",
"/",
"--chdir",
])
.arg(&cwd)
.arg("--clearenv");
} else {
cmd.current_dir(&cwd);
}
for path in [&registry, &tools] {
cmd.arg("--ro-bind").arg(path).arg(path);
}
cmd.args([
"--proc",
"/proc",
"--dev",
"/dev",
"--remount-ro",
"/",
"--chdir",
])
.arg(&cwd)
.args(["--clearenv", "--setenv", "PATH"])
.arg(std::env::var("PATH")?)
.args(["--setenv", "HOME", "/nonexistent", "--setenv", "CARGO_HOME"])
.arg(&registry)
.args(["--setenv", "CARGO_TARGET_DIR"])
.arg(&target)
.args(["--setenv", "KACHE_CACHE_DIR"])
.arg(&cache)
.args(["--setenv", "SAUSAGE_CWD_INIT"])
.arg(tools.join("init.o"))
.args(["--setenv", "SAUSAGE_RUN_PATH"])
.arg(&run_path);
let mut environment = vec![
("PATH", std::env::var_os("PATH").context("PATH missing")?),
("HOME", "/nonexistent".into()),
("CARGO_HOME", registry.clone().into_os_string()),
("CARGO_TARGET_DIR", target.clone().into_os_string()),
("KACHE_CACHE_DIR", cache.clone().into_os_string()),
("SAUSAGE_CWD_INIT", tools.join("init.o").into_os_string()),
("SAUSAGE_RUN_PATH", run_path.clone().into_os_string()),
];
for name in [
"CC_wasm32_wasip2",
"AR_wasm32_wasip2",
"CFLAGS_wasm32_wasip2",
] {
if let Ok(value) = std::env::var(name) {
environment.push((name, value.into()));
}
}
for (name, value) in environment {
if self.no_sandbox {
cmd.env(name, value);
} else {
cmd.args(["--setenv", name]).arg(value);
}
}
cmd.args(["cargo", "--offline", "--config"])
if !self.no_sandbox {
cmd.arg("cargo");
}
cmd.args(["--offline", "--config"])
.arg(format!("build.rustc-wrapper={:?}", kache))
.arg("--config")
.arg(format!(