crates/heimdall-seccomp/tests/arch.rs
// SPDX-License-Identifier: AGPL-3.0-only
//! The syscall tables and the libc detection. Heimdall is a defensive
//! sandbox; these tests only read its own tables and its own test binary.
use heimdall_seccomp::{Arch, Libc};
#[test]
fn x86_64_numbers_match_the_kernel_abi() {
let a = Arch::X86_64;
for (name, nr) in [
("read", 0),
("write", 1),
("open", 2),
("mmap", 9),
("mprotect", 10),
("ioctl", 16),
("socket", 41),
("clone", 56),
("execve", 59),
("fcntl", 72),
("prctl", 157),
("openat", 257),
("execveat", 322),
("clone3", 435),
] {
assert_eq!(a.syscall_nr(name), Some(nr), "{name}");
assert_eq!(a.syscall_name(nr), Some(name), "{nr}");
}
}
#[test]
fn aarch64_numbers_match_the_generic_abi() {
let a = Arch::Aarch64;
for (name, nr) in [
("fcntl", 25),
("ioctl", 29),
("openat", 56),
("read", 63),
("write", 64),
("newfstatat", 79),
("prctl", 167),
("socket", 198),
("clone", 220),
("execve", 221),
("mmap", 222),
("mprotect", 226),
("execveat", 281),
("clone3", 435),
] {
assert_eq!(a.syscall_nr(name), Some(nr), "{name}");
assert_eq!(a.syscall_name(nr), Some(name), "{nr}");
}
}
#[test]
fn aarch64_has_no_legacy_x86_calls() {
for name in ["open", "stat", "fork", "poll", "select", "arch_prctl"] {
assert_eq!(Arch::Aarch64.syscall_nr(name), None, "{name}");
}
}
#[test]
fn tables_are_sorted_by_number_and_names_and_numbers_are_unique() {
for a in [Arch::X86_64, Arch::Aarch64] {
let t = a.syscalls();
assert!(t.len() > 300, "{a}: only {} calls", t.len());
assert!(
t.windows(2).all(|w| w[0].1 < w[1].1),
"{a}: not strictly sorted"
);
let mut names: Vec<_> = t.iter().map(|(n, _)| *n).collect();
names.sort_unstable();
names.dedup();
assert_eq!(names.len(), t.len(), "{a}: duplicate names");
}
}
#[test]
fn audit_arch_values_round_trip() {
for a in [Arch::X86_64, Arch::Aarch64] {
assert_eq!(Arch::from_audit_arch(a.audit_arch()), Some(a));
assert_eq!(a.as_str().parse::<Arch>(), Ok(a));
}
assert_eq!(Arch::X86_64.audit_arch(), 0xC000_003E);
assert_eq!(Arch::Aarch64.audit_arch(), 0xC000_00B7);
assert_eq!(
Arch::from_audit_arch(0x4000_0003),
None,
"i386 is not supported"
);
}
#[test]
fn libc_names_parse_and_print() {
for l in [Libc::Glibc, Libc::Musl] {
assert_eq!(l.as_str().parse::<Libc>(), Ok(l));
}
assert!("bionic".parse::<Libc>().is_err());
}
#[test]
fn libc_detect_reads_the_interpreter_of_this_test_binary() {
let me = std::fs::read(std::env::current_exe().unwrap()).unwrap();
let want = if cfg!(target_env = "musl") {
Libc::Musl
} else {
Libc::Glibc
};
assert_eq!(Libc::detect(&me), Some(want));
}
#[test]
fn libc_detect_of_garbage_is_none() {
assert_eq!(Libc::detect(b"not an elf at all"), None);
assert_eq!(Libc::detect(b"\x7fELF"), None);
}