use crate::common::*; #[test] fn seccomp_on_by_default_blocks_unshare() { let output = Sandbox::new(&[]) .args(["--", "unshare", "--user", "--map-root-user", "/bin/true"]) .output() .expect("agent-sandbox binary failed to execute"); assert!( !output.status.success(), "expected unshare(2) to be blocked by default seccomp filter, but it succeeded" ); } #[test] fn seccomp_off_allows_blocked_syscall() { let output = Sandbox::new(&["--no-seccomp"]) .args(["--", "unshare", "--user", "--map-root-user", "/bin/true"]) .output() .expect("agent-sandbox binary failed to execute"); assert!( output.status.success(), "expected unshare(2) to succeed without seccomp, stderr: {}", String::from_utf8_lossy(&output.stderr) ); } #[test] fn seccomp_dry_run_emits_seccomp_arg() { let output = Sandbox::new(&["--dry-run"]) .args(["--", "/bin/true"]) .output() .expect("agent-sandbox binary failed to execute"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( stdout.contains("--seccomp"), "expected --seccomp in dry-run output, got: {stdout}" ); } #[test] fn seccomp_dry_run_no_seccomp_omits_arg() { let output = Sandbox::new(&["--dry-run", "--no-seccomp"]) .args(["--", "/bin/true"]) .output() .expect("agent-sandbox binary failed to execute"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( !stdout.contains("--seccomp"), "expected no --seccomp in dry-run output with --no-seccomp, got: {stdout}" ); } #[test] fn seccomp_normal_workload_succeeds() { let output = Sandbox::new(&[]) .args(["--", "bash", "-c", "ls /etc > /dev/null && date"]) .output() .expect("agent-sandbox binary failed to execute"); assert!( output.status.success(), "expected normal workload to succeed under default seccomp, stderr: {}", String::from_utf8_lossy(&output.stderr) ); } #[test] fn seccomp_bash_pthread_fallback_works() { // Verifies the ENOSYS-not-EPERM choice for clone3 doesn't break libc's // clone3 -> clone fallback path that bash uses internally. let output = Sandbox::new(&[]) .args(["--", "bash", "-c", "true"]) .output() .expect("agent-sandbox binary failed to execute"); assert!( output.status.success(), "expected bash to succeed under default seccomp (clone3 fallback), stderr: {}", String::from_utf8_lossy(&output.stderr) ); } #[test] fn seccomp_blocks_tiocsti() { // TIOCSTI (0x5412) injects keystrokes into the terminal input queue. // Without --new-session, this is the primary defense against CVE-2017-5226. // // On kernels >= 6.2 with CONFIG_LEGACY_TIOCSTI=n, the kernel blocks TIOCSTI // before seccomp sees it. We test with --no-seccomp first to detect that and // skip, so the test only asserts our filter's behaviour. let baseline = Sandbox::new(&["--no-seccomp"]) .args([ "--", "python3", "-c", "import fcntl; fcntl.ioctl(0, 0x5412, b'x')", ]) .output() .expect("agent-sandbox binary failed to execute"); if !baseline.status.success() { // Kernel already blocks TIOCSTI; seccomp filter is untestable here. return; } let output = Sandbox::new(&[]) .args([ "--", "python3", "-c", "import fcntl; fcntl.ioctl(0, 0x5412, b'x')", ]) .output() .expect("agent-sandbox binary failed to execute"); assert!( !output.status.success(), "expected TIOCSTI to be blocked by seccomp filter" ); }