Mark inherited descriptors close-on-exec so none reach the sandbox

This commit is contained in:
2026-11-04 18:12:04 +01:00
parent 14c4f44a1f
commit f9ac595d63
4 changed files with 66 additions and 0 deletions
+38
View File
@@ -1,4 +1,6 @@
use std::fs;
use std::os::fd::AsRawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use tempfile::TempDir;
@@ -496,6 +498,42 @@ fn persistent_tmp_leaks_no_descriptor_into_host_tmp() {
);
}
#[test]
fn inherited_host_descriptor_does_not_reach_sandbox() {
const PASSED_FD: i32 = 9;
let host_dir = TempDir::new().unwrap();
fs::write(host_dir.path().join("canary"), "host-secret").unwrap();
let host_dir_handle = fs::File::open(host_dir.path()).unwrap();
let host_dir_fd = host_dir_handle.as_raw_fd();
let mut sandbox = Sandbox::new(&[]);
sandbox.args([
"--",
"bash",
"-c",
&format!("cat /proc/self/fd/{PASSED_FD}/canary 2>/dev/null; true"),
]);
unsafe {
sandbox.pre_exec(move || match libc::dup2(host_dir_fd, PASSED_FD) {
-1 => Err(std::io::Error::last_os_error()),
_ => Ok(()),
});
}
let output = sandbox
.output()
.expect("agent-sandbox binary failed to execute");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
assert!(
!String::from_utf8_lossy(&output.stdout).contains("host-secret"),
"a descriptor inherited by agent-sandbox reaches the sandboxed command"
);
}
#[test]
fn persistent_tmp_is_noop_in_blacklist_mode() {
let label = format!("e2e-bl-noop-{}-{}", std::process::id(), rand_suffix());