use sandbox_seccomp::{SeccompBpf, SeccompFilter, SeccompProfile};
#[test]
fn seccomp_minimal_blocks_socket() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed: {}", std::io::Error::last_os_error());
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Minimal);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
libc::syscall(libc::SYS_socket, libc::AF_INET, libc::SOCK_STREAM, 0);
libc::_exit(42);
} else {
let mut status: i32 = 0;
let ret = libc::waitpid(pid, &mut status, 0);
assert_eq!(ret, pid);
assert!(
libc::WIFSIGNALED(status),
"Child should have been killed by signal, status=0x{:x}",
status
);
let sig = libc::WTERMSIG(status);
assert_eq!(
sig,
libc::SIGSYS,
"Expected SIGSYS ({}), got signal {}",
libc::SIGSYS,
sig
);
}
}
}
#[test]
fn seccomp_minimal_allows_basic_io() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Minimal);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
let _ = libc::getpid();
let buf = b"ok\n";
libc::write(libc::STDOUT_FILENO, buf.as_ptr() as *const libc::c_void, 3);
libc::_exit(0);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status),
"Child should have exited normally, status=0x{:x}",
status
);
assert_eq!(
libc::WEXITSTATUS(status),
0,
"Child should exit with 0 (allowed syscalls worked)"
);
}
}
}
#[test]
fn seccomp_block_specific_syscall() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let mut filter = SeccompFilter::from_profile(SeccompProfile::Minimal);
filter.block_syscall("getpid");
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
libc::getpid();
libc::_exit(42);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFSIGNALED(status),
"Child should have been killed by signal"
);
assert_eq!(libc::WTERMSIG(status), libc::SIGSYS);
}
}
}
#[test]
fn seccomp_network_allows_socket() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Network);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
let fd = libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0);
if fd >= 0 {
libc::close(fd);
libc::_exit(0);
} else {
libc::_exit(0);
}
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status),
"Child should have exited normally (socket allowed in Network profile)"
);
assert_eq!(libc::WEXITSTATUS(status), 0);
}
}
}
#[test]
fn seccomp_essential_allows_bootstrap() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Essential);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
let _ = libc::getpid();
let buf = b"ok\n";
libc::write(libc::STDOUT_FILENO, buf.as_ptr() as *const libc::c_void, 3);
libc::_exit(0);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status),
"Child should have exited normally, status=0x{:x}",
status
);
assert_eq!(
libc::WEXITSTATUS(status),
0,
"Child should exit with 0 (bootstrap syscalls worked)"
);
}
}
}
#[test]
fn seccomp_essential_blocks_socket() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Essential);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
libc::syscall(libc::SYS_socket, libc::AF_INET, libc::SOCK_STREAM, 0);
libc::_exit(42);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFSIGNALED(status),
"Child should have been killed by signal, status=0x{:x}",
status
);
assert_eq!(libc::WTERMSIG(status), libc::SIGSYS);
}
}
}
#[test]
fn seccomp_network_includes_mkdir_from_io_heavy() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Network);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
let path = b"/tmp/seccomp_cumulative_test_dir\0";
let ret = libc::mkdir(path.as_ptr() as *const libc::c_char, 0o755);
if ret == 0 {
libc::rmdir(path.as_ptr() as *const libc::c_char);
}
libc::_exit(0);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status),
"Child should have exited normally (mkdir allowed in Network via cumulative IoHeavy)"
);
assert_eq!(libc::WEXITSTATUS(status), 0);
}
}
}
#[test]
fn seccomp_all_profiles_load_successfully() {
for profile in SeccompProfile::all() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed for profile {:?}", profile);
if pid == 0 {
let filter = SeccompFilter::from_profile(profile);
match SeccompBpf::load(&filter) {
Ok(()) => libc::_exit(0),
Err(_) => libc::_exit(1),
}
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status) && libc::WEXITSTATUS(status) == 0,
"Profile {:?} should load successfully",
profile
);
}
}
}
}
#[test]
fn seccomp_minimal_allows_runtime_essentials() {
unsafe {
let pid = libc::fork();
assert!(pid >= 0, "fork failed");
if pid == 0 {
let filter = SeccompFilter::from_profile(SeccompProfile::Minimal);
if SeccompBpf::load(&filter).is_err() {
libc::_exit(99);
}
libc::lseek(libc::STDIN_FILENO, 0, libc::SEEK_CUR);
libc::syscall(libc::SYS_gettid);
let mut cpuset: libc::cpu_set_t = std::mem::zeroed();
libc::sched_getaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &mut cpuset);
let mut info: libc::sysinfo = std::mem::zeroed();
libc::sysinfo(&mut info);
libc::_exit(0);
} else {
let mut status: i32 = 0;
libc::waitpid(pid, &mut status, 0);
assert!(
libc::WIFEXITED(status),
"Child should have exited normally (runtime-essential syscalls allowed), status=0x{:x}",
status
);
assert_eq!(
libc::WEXITSTATUS(status),
0,
"Child should exit with 0 (all runtime-essential syscalls worked)"
);
}
}
}