Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/heimdall

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);
}