118 lines
3.2 KiB
Rust
118 lines
3.2 KiB
Rust
use std::fs;
|
|
|
|
use tempfile::TempDir;
|
|
|
|
use crate::common::*;
|
|
|
|
fn read_sid_from_stat(stat: &str) -> u32 {
|
|
stat.split_whitespace()
|
|
.nth(5)
|
|
.expect("missing field 6 in /proc/self/stat")
|
|
.parse()
|
|
.expect("failed to parse session ID")
|
|
}
|
|
|
|
fn read_sid_inside_sandbox(extra_args: &[&str]) -> u32 {
|
|
let output = sandbox(extra_args)
|
|
.args(["--", "bash", "-c", "cat /proc/self/stat"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
read_sid_from_stat(&String::from_utf8_lossy(&output.stdout))
|
|
}
|
|
|
|
fn read_sid_current_process() -> u32 {
|
|
let stat = fs::read_to_string("/proc/self/stat").expect("failed to read /proc/self/stat");
|
|
read_sid_from_stat(&stat)
|
|
}
|
|
#[test]
|
|
fn unshare_net_blocks_network() {
|
|
let output = sandbox(&["--unshare-net"])
|
|
.args([
|
|
"--",
|
|
"bash",
|
|
"-c",
|
|
"curl -s --max-time 2 http://1.1.1.1 2>&1; echo $?",
|
|
])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(
|
|
!stdout.trim().ends_with("0"),
|
|
"expected curl to fail, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn hardened_pid_namespace() {
|
|
let output = sandbox(&["--hardened"])
|
|
.args(["--", "bash", "-c", "ls /proc | grep -cE '^[0-9]+$'"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let count: u32 = String::from_utf8_lossy(&output.stdout)
|
|
.trim()
|
|
.parse()
|
|
.unwrap_or(999);
|
|
assert!(
|
|
count < 10,
|
|
"expected isolated PID namespace with few PIDs, got {count}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn chdir_override() {
|
|
let dir = TempDir::new().expect("failed to create temp dir");
|
|
let dir_str = dir.path().to_str().unwrap();
|
|
|
|
let output = sandbox(&["--chdir", dir_str])
|
|
.args(["--", "bash", "-c", "pwd"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
assert_eq!(
|
|
stdout, dir_str,
|
|
"expected cwd to be {dir_str}, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn chdir_under_hardened_tmp() {
|
|
let dir = TempDir::new().expect("failed to create temp dir");
|
|
let dir_str = dir.path().to_str().unwrap();
|
|
|
|
let output = sandbox(&["--hardened", "--chdir", dir_str])
|
|
.args(["--", "bash", "-c", "pwd && touch ./ok && echo done"])
|
|
.output()
|
|
.expect("agent-sandbox binary failed to execute");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(
|
|
stdout.contains("done"),
|
|
"expected chdir under /tmp to work with --hardened, got: {stdout}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn hardened_isolates_sid() {
|
|
let inner_sid = read_sid_inside_sandbox(&["--hardened"]);
|
|
let outer_sid = read_sid_current_process();
|
|
|
|
assert_ne!(
|
|
inner_sid, outer_sid,
|
|
"sandboxed process should have a different session ID (got {inner_sid} == {outer_sid})"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn default_mode_shares_session() {
|
|
let inner_sid = read_sid_inside_sandbox(&[]);
|
|
let outer_sid = read_sid_current_process();
|
|
|
|
assert_eq!(
|
|
inner_sid, outer_sid,
|
|
"default-mode sandbox should share the session ID (got {inner_sid} != {outer_sid})"
|
|
);
|
|
}
|