use reverie::syscalls::Sysno;
const EXPECTED_X86_64_SYSNO_COUNT: usize = 373;
const _: () = {
assert!(Sysno::count() == EXPECTED_X86_64_SYSNO_COUNT);
assert!(Sysno::last().id() == 461);
};
pub(crate) fn all_pinned_syscalls() -> impl Iterator<Item = Sysno> {
Sysno::iter().chain(std::iter::once(Sysno::last()))
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub(crate) enum SyscallClassification {
Determinized,
PassThrough,
Unsupported,
}
pub(crate) const fn classify_syscall(sysno: Sysno) -> SyscallClassification {
match sysno {
Sysno::accept
| Sysno::accept4
| Sysno::alarm
| Sysno::arch_prctl
| Sysno::bind
| Sysno::clock_getres
| Sysno::clock_gettime
| Sysno::clock_nanosleep
| Sysno::clone
| Sysno::clone3
| Sysno::close
| Sysno::connect
| Sysno::creat
| Sysno::dup
| Sysno::dup2
| Sysno::dup3
| Sysno::epoll_create
| Sysno::epoll_create1
| Sysno::epoll_ctl
| Sysno::epoll_ctl_old
| Sysno::epoll_pwait
| Sysno::epoll_pwait2
| Sysno::epoll_wait
| Sysno::epoll_wait_old
| Sysno::eventfd
| Sysno::eventfd2
| Sysno::execve
| Sysno::execveat
| Sysno::exit
| Sysno::exit_group
| Sysno::fadvise64
| Sysno::fcntl
| Sysno::fork
| Sysno::fstat
| Sysno::fstatfs
| Sysno::futex
| Sysno::futex_requeue
| Sysno::futex_wait
| Sysno::futex_waitv
| Sysno::futex_wake
| Sysno::futimesat
| Sysno::getcpu
| Sysno::getdents
| Sysno::getdents64
| Sysno::getitimer
| Sysno::getrandom
| Sysno::getrusage
| Sysno::gettimeofday
| Sysno::inotify_add_watch
| Sysno::inotify_init
| Sysno::inotify_init1
| Sysno::inotify_rm_watch
| Sysno::io_uring_enter
| Sysno::io_uring_register
| Sysno::io_uring_setup
| Sysno::ioctl
| Sysno::lstat
| Sysno::madvise
| Sysno::membarrier
| Sysno::memfd_create
| Sysno::mincore
| Sysno::mmap
| Sysno::mremap
| Sysno::munmap
| Sysno::nanosleep
| Sysno::newfstatat
| Sysno::open
| Sysno::openat
| Sysno::pause
| Sysno::pipe
| Sysno::pipe2
| Sysno::poll
| Sysno::ppoll
| Sysno::pselect6
| Sysno::select
| Sysno::prlimit64
| Sysno::pread64
| Sysno::lseek
| Sysno::pwrite64
| Sysno::readv
| Sysno::preadv
| Sysno::preadv2
| Sysno::pwritev
| Sysno::pwritev2
| Sysno::read
| Sysno::recvfrom
| Sysno::recvmsg
| Sysno::recvmmsg
| Sysno::rseq
| Sysno::rt_sigaction
| Sysno::rt_sigprocmask
| Sysno::rt_sigtimedwait
| Sysno::rt_sigsuspend
| Sysno::sched_getaffinity
| Sysno::sched_setaffinity
| Sysno::sched_yield
| Sysno::sendmmsg
| Sysno::sendmsg
| Sysno::sendto
| Sysno::setpgid
| Sysno::setsid
| Sysno::signalfd
| Sysno::signalfd4
| Sysno::socket
| Sysno::socketpair
| Sysno::stat
| Sysno::statfs
| Sysno::statx
| Sysno::sysinfo
| Sysno::times
| Sysno::time
| Sysno::timer_create
| Sysno::timer_delete
| Sysno::timer_getoverrun
| Sysno::timer_gettime
| Sysno::timer_settime
| Sysno::timerfd_create
| Sysno::timerfd_gettime
| Sysno::timerfd_settime
| Sysno::uname
| Sysno::userfaultfd
| Sysno::utime
| Sysno::utimensat
| Sysno::utimes
| Sysno::vfork
| Sysno::wait4
| Sysno::waitid
| Sysno::write
| Sysno::clock_settime
| Sysno::getpeername
| Sysno::getsockname
| Sysno::getsockopt
| Sysno::getpriority
| Sysno::getrlimit
| Sysno::kill
| Sysno::listen
| Sysno::prctl
| Sysno::rt_sigpending
| Sysno::setitimer
| Sysno::setpriority
| Sysno::process_madvise
| Sysno::setrlimit
| Sysno::setsockopt
| Sysno::shutdown
| Sysno::seccomp
| Sysno::tgkill
| Sysno::tkill
| Sysno::rt_sigqueueinfo
| Sysno::rt_tgsigqueueinfo
| Sysno::_sysctl
| Sysno::afs_syscall
| Sysno::create_module
| Sysno::get_kernel_syms
| Sysno::getpmsg
| Sysno::lookup_dcookie
| Sysno::nfsservctl
| Sysno::putpmsg
| Sysno::query_module
| Sysno::security
| Sysno::tuxcall
| Sysno::uselib
| Sysno::vserver
| Sysno::init_module
| Sysno::finit_module
| Sysno::delete_module
| Sysno::kexec_load
| Sysno::kexec_file_load
| Sysno::reboot
| Sysno::swapon
| Sysno::swapoff
| Sysno::ioperm
| Sysno::iopl
| Sysno::pivot_root
| Sysno::sethostname
| Sysno::setdomainname
| Sysno::vhangup
| Sysno::quotactl
| Sysno::quotactl_fd
| Sysno::writev
| Sysno::mbind
| Sysno::set_mempolicy
| Sysno::get_mempolicy
| Sysno::set_mempolicy_home_node
| Sysno::migrate_pages
| Sysno::move_pages
| Sysno::sched_setscheduler
| Sysno::sched_setparam
| Sysno::sched_getscheduler
| Sysno::sched_getparam
| Sysno::sched_rr_get_interval
| Sysno::mount
| Sysno::umount2
| Sysno::mount_setattr
| Sysno::move_mount
| Sysno::open_tree
| Sysno::fsopen
| Sysno::fsmount
| Sysno::fsconfig
| Sysno::fspick
| Sysno::unshare
| Sysno::setns
| Sysno::open_by_handle_at
| Sysno::fanotify_init
| Sysno::fanotify_mark
| Sysno::settimeofday
| Sysno::sysfs
| Sysno::statmount
| Sysno::listmount
| Sysno::ustat
| Sysno::io_setup
| Sysno::io_destroy
| Sysno::io_submit
| Sysno::io_cancel
| Sysno::io_getevents
| Sysno::io_pgetevents
| Sysno::mq_open
| Sysno::mq_unlink
| Sysno::mq_timedsend
| Sysno::mq_timedreceive
| Sysno::mq_notify
| Sysno::mq_getsetattr
| Sysno::msgget
| Sysno::msgsnd
| Sysno::msgrcv
| Sysno::msgctl
| Sysno::perf_event_open
| Sysno::remap_file_pages
| Sysno::semctl
| Sysno::semget
| Sysno::semop
| Sysno::semtimedop
| Sysno::shmat
| Sysno::shmctl
| Sysno::shmdt
| Sysno::shmget
| Sysno::landlock_create_ruleset
| Sysno::landlock_add_rule
| Sysno::landlock_restrict_self
| Sysno::add_key
| Sysno::request_key
| Sysno::keyctl
| Sysno::close_range
| Sysno::sendfile
| Sysno::copy_file_range
| Sysno::splice
| Sysno::tee
| Sysno::vmsplice
| Sysno::lsm_get_self_attr
| Sysno::lsm_set_self_attr
| Sysno::name_to_handle_at
| Sysno::acct
| Sysno::process_vm_readv
| Sysno::process_vm_writev
| Sysno::memfd_secret
| Sysno::process_mrelease
| Sysno::map_shadow_stack
| Sysno::bpf
| Sysno::cachestat
| Sysno::lsm_list_modules
| Sysno::ptrace
| Sysno::kcmp
| Sysno::pidfd_open
| Sysno::pidfd_send_signal
| Sysno::pidfd_getfd
| Sysno::readlink
| Sysno::readlinkat
| Sysno::flock
| Sysno::ioprio_set
| Sysno::sched_getattr
| Sysno::adjtimex
| Sysno::clock_adjtime
| Sysno::syslog
| Sysno::ioprio_get
| Sysno::sched_setattr
| Sysno::openat2
| Sysno::setuid
| Sysno::setgid
| Sysno::setresuid
| Sysno::setresgid
| Sysno::setreuid
| Sysno::setregid
| Sysno::setgroups
| Sysno::setfsuid
| Sysno::setfsgid
| Sysno::getuid
| Sysno::geteuid
| Sysno::getgid
| Sysno::getegid
| Sysno::getresuid
| Sysno::getresgid
| Sysno::chown
| Sysno::fchown
| Sysno::fchownat
| Sysno::lchown => SyscallClassification::Determinized,
Sysno::access
| Sysno::brk
| Sysno::getcwd
| Sysno::getpid
| Sysno::getpgid
| Sysno::getpgrp
| Sysno::getppid
| Sysno::getsid
| Sysno::gettid
| Sysno::mprotect
| Sysno::get_robust_list
| Sysno::set_robust_list
| Sysno::set_tid_address
| Sysno::sigaltstack
| Sysno::capget
| Sysno::capset
| Sysno::getgroups
| Sysno::chdir
| Sysno::faccessat2
| Sysno::fchdir
| Sysno::umask
| Sysno::chmod
| Sysno::fchmodat
| Sysno::linkat
| Sysno::mkdir
| Sysno::mkdirat
| Sysno::renameat2
| Sysno::rmdir
| Sysno::symlinkat
| Sysno::unlink
| Sysno::unlinkat
| Sysno::getxattr
| Sysno::lgetxattr
| Sysno::removexattr
| Sysno::setxattr
| Sysno::fdatasync
| Sysno::ftruncate
| Sysno::fsync
| Sysno::munlock
| Sysno::munlockall
| Sysno::fallocate
| Sysno::rename
| Sysno::renameat
| Sysno::truncate
| Sysno::faccessat
| Sysno::fchmod
| Sysno::fchmodat2
| Sysno::fgetxattr
| Sysno::flistxattr
| Sysno::fremovexattr
| Sysno::fsetxattr
| Sysno::link
| Sysno::listxattr
| Sysno::llistxattr
| Sysno::lremovexattr
| Sysno::lsetxattr
| Sysno::msync
| Sysno::readahead
| Sysno::symlink
| Sysno::sync_file_range
| Sysno::rt_sigreturn => SyscallClassification::PassThrough,
Sysno::chroot
| Sysno::get_thread_area
| Sysno::mknod
| Sysno::mknodat
| Sysno::mlock
| Sysno::mlock2
| Sysno::mlockall
| Sysno::modify_ldt
| Sysno::personality
| Sysno::pkey_alloc
| Sysno::pkey_free
| Sysno::pkey_mprotect
| Sysno::sched_get_priority_max
| Sysno::sched_get_priority_min
| Sysno::set_thread_area
| Sysno::sync
| Sysno::syncfs
=> SyscallClassification::PassThrough,
Sysno::restart_syscall
=> SyscallClassification::Unsupported,
_unexpected => panic!("unclassified Sysno outside pinned ABI"),
}
}
pub(crate) const fn is_unimplemented_enosys_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::_sysctl
| Sysno::afs_syscall
| Sysno::create_module
| Sysno::get_kernel_syms
| Sysno::getpmsg
| Sysno::lookup_dcookie
| Sysno::nfsservctl
| Sysno::putpmsg
| Sysno::query_module
| Sysno::security
| Sysno::tuxcall
| Sysno::uselib
| Sysno::vserver
)
}
pub(crate) const fn is_futex2_enosys_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::futex_requeue | Sysno::futex_wait | Sysno::futex_waitv | Sysno::futex_wake
)
}
pub(crate) const fn is_privileged_admin_refused_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::init_module
| Sysno::finit_module
| Sysno::delete_module
| Sysno::kexec_load
| Sysno::kexec_file_load
| Sysno::reboot
| Sysno::swapon
| Sysno::swapoff
| Sysno::ioperm
| Sysno::iopl
| Sysno::pivot_root
| Sysno::sethostname
| Sysno::setdomainname
| Sysno::vhangup
| Sysno::quotactl
| Sysno::quotactl_fd
)
}
pub(crate) const fn is_mount_ns_admin_refused_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::mount
| Sysno::umount2
| Sysno::mount_setattr
| Sysno::move_mount
| Sysno::open_tree
| Sysno::fsopen
| Sysno::fsmount
| Sysno::fsconfig
| Sysno::fspick
| Sysno::unshare
| Sysno::setns
| Sysno::open_by_handle_at
| Sysno::fanotify_init
| Sysno::fanotify_mark
| Sysno::settimeofday
)
}
pub(crate) const fn is_credential_identity_noop_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::setuid
| Sysno::setgid
| Sysno::setresuid
| Sysno::setresgid
| Sysno::setreuid
| Sysno::setregid
| Sysno::setgroups
| Sysno::setfsuid
| Sysno::setfsgid
)
}
pub(crate) const fn is_ownership_change_noop_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::chown | Sysno::fchown | Sysno::fchownat | Sysno::lchown
)
}
pub(crate) const fn is_unsupported_async_ipc_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::io_setup
| Sysno::io_destroy
| Sysno::io_submit
| Sysno::io_cancel
| Sysno::io_getevents
| Sysno::io_pgetevents
| Sysno::mq_open
| Sysno::mq_unlink
| Sysno::mq_timedsend
| Sysno::mq_timedreceive
| Sysno::mq_notify
| Sysno::mq_getsetattr
| Sysno::msgget
| Sysno::msgsnd
| Sysno::msgrcv
| Sysno::msgctl
| Sysno::semctl
| Sysno::semget
| Sysno::semop
| Sysno::semtimedop
| Sysno::shmat
| Sysno::shmctl
| Sysno::shmdt
| Sysno::shmget
)
}
pub(crate) const fn is_remap_file_pages_enosys_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::remap_file_pages
)
}
pub(crate) const fn is_landlock_sandbox_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::landlock_create_ruleset | Sysno::landlock_add_rule | Sysno::landlock_restrict_self
)
}
pub(crate) const fn is_process_isolation_refused_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::acct
| Sysno::process_vm_readv
| Sysno::process_vm_writev
)
}
pub(crate) const fn is_privileged_observation_refused_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::ptrace
| Sysno::kcmp
)
}
pub(crate) const fn is_perf_event_enosys_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::perf_event_open
)
}
pub(crate) const fn is_mount_introspection_enosys_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::sysfs
| Sysno::statmount
| Sysno::listmount
| Sysno::ustat
)
}
pub(crate) const fn is_host_security_identity_probe_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::lsm_get_self_attr
| Sysno::lsm_set_self_attr
)
}
pub(crate) const fn is_zero_copy_pipe_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::splice
| Sysno::tee
| Sysno::vmsplice
)
}
pub(crate) const fn is_kernel_keyring_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::add_key
| Sysno::request_key
| Sysno::keyctl
)
}
pub(crate) const fn is_optional_memory_feature_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::memfd_secret | Sysno::process_mrelease | Sysno::map_shadow_stack
)
}
pub(crate) const fn is_host_kernel_probe_syscall(sysno: Sysno) -> bool {
matches!(
sysno,
Sysno::bpf
| Sysno::cachestat
| Sysno::lsm_list_modules
)
}
pub(crate) const fn is_strict_only_deterministic_refusal_syscall(sysno: Sysno) -> bool {
matches!(sysno, Sysno::rseq)
|| is_zero_copy_pipe_syscall(sysno)
|| is_kernel_keyring_syscall(sysno)
}
pub(crate) const fn is_deterministically_refused_syscall(sysno: Sysno) -> bool {
is_strict_only_deterministic_refusal_syscall(sysno)
|| is_unimplemented_enosys_syscall(sysno)
|| is_futex2_enosys_syscall(sysno)
|| is_privileged_admin_refused_syscall(sysno)
|| is_mount_ns_admin_refused_syscall(sysno)
|| is_unsupported_async_ipc_syscall(sysno)
|| is_remap_file_pages_enosys_syscall(sysno)
|| is_landlock_sandbox_syscall(sysno)
|| is_process_isolation_refused_syscall(sysno)
|| is_privileged_observation_refused_syscall(sysno)
|| is_perf_event_enosys_syscall(sysno)
|| is_mount_introspection_enosys_syscall(sysno)
|| is_host_security_identity_probe_syscall(sysno)
|| is_optional_memory_feature_syscall(sysno)
|| is_host_kernel_probe_syscall(sysno)
|| matches!(
sysno,
Sysno::openat2
| Sysno::copy_file_range
| Sysno::clock_settime
| Sysno::futimesat
| Sysno::io_uring_setup
| Sysno::io_uring_enter
| Sysno::io_uring_register
| Sysno::name_to_handle_at
| Sysno::epoll_ctl_old
)
}
#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use super::*;
const DETERMINIZED_SYSCALLS: &[&str] = &[
"_sysctl",
"accept",
"accept4",
"acct",
"add_key",
"adjtimex",
"afs_syscall",
"alarm",
"arch_prctl",
"bind",
"bpf",
"cachestat",
"chown",
"clock_adjtime",
"clock_getres",
"clock_gettime",
"clock_nanosleep",
"clock_settime",
"clone",
"clone3",
"close",
"close_range",
"connect",
"copy_file_range",
"creat",
"create_module",
"delete_module",
"dup",
"dup2",
"dup3",
"epoll_create",
"epoll_create1",
"epoll_ctl",
"epoll_ctl_old",
"epoll_pwait",
"epoll_pwait2",
"epoll_wait",
"epoll_wait_old",
"eventfd",
"eventfd2",
"execve",
"execveat",
"exit",
"exit_group",
"fadvise64",
"fanotify_init",
"fanotify_mark",
"fchown",
"fchownat",
"fcntl",
"finit_module",
"flock",
"fork",
"fsconfig",
"fsmount",
"fsopen",
"fspick",
"fstat",
"fstatfs",
"futex",
"futex_requeue",
"futex_wait",
"futex_waitv",
"futex_wake",
"futimesat",
"get_kernel_syms",
"get_mempolicy",
"getcpu",
"getdents",
"getdents64",
"getegid",
"geteuid",
"getgid",
"getitimer",
"getpeername",
"getpmsg",
"getpriority",
"getrandom",
"getresgid",
"getresuid",
"getrlimit",
"getrusage",
"getsockname",
"getsockopt",
"gettimeofday",
"getuid",
"init_module",
"inotify_add_watch",
"inotify_init",
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
"io_destroy",
"io_getevents",
"io_pgetevents",
"io_setup",
"io_submit",
"io_uring_enter",
"io_uring_register",
"io_uring_setup",
"ioctl",
"ioperm",
"iopl",
"ioprio_get",
"ioprio_set",
"kcmp",
"kexec_file_load",
"kexec_load",
"keyctl",
"kill",
"landlock_add_rule",
"landlock_create_ruleset",
"landlock_restrict_self",
"lchown",
"listen",
"listmount",
"lookup_dcookie",
"lseek",
"lsm_get_self_attr",
"lsm_list_modules",
"lsm_set_self_attr",
"lstat",
"madvise",
"map_shadow_stack",
"mbind",
"membarrier",
"memfd_create",
"memfd_secret",
"migrate_pages",
"mincore",
"mmap",
"mount",
"mount_setattr",
"move_mount",
"move_pages",
"mq_getsetattr",
"mq_notify",
"mq_open",
"mq_timedreceive",
"mq_timedsend",
"mq_unlink",
"mremap",
"msgctl",
"msgget",
"msgrcv",
"msgsnd",
"munmap",
"name_to_handle_at",
"nanosleep",
"newfstatat",
"nfsservctl",
"open",
"open_by_handle_at",
"open_tree",
"openat",
"openat2",
"pause",
"perf_event_open",
"pidfd_getfd",
"pidfd_open",
"pidfd_send_signal",
"pipe",
"pipe2",
"pivot_root",
"poll",
"ppoll",
"prctl",
"pread64",
"preadv",
"preadv2",
"prlimit64",
"process_madvise",
"process_mrelease",
"process_vm_readv",
"process_vm_writev",
"pselect6",
"ptrace",
"putpmsg",
"pwrite64",
"pwritev",
"pwritev2",
"query_module",
"quotactl",
"quotactl_fd",
"read",
"readlink",
"readlinkat",
"readv",
"reboot",
"recvfrom",
"recvmmsg",
"recvmsg",
"remap_file_pages",
"request_key",
"rseq",
"rt_sigaction",
"rt_sigpending",
"rt_sigprocmask",
"rt_sigqueueinfo",
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_tgsigqueueinfo",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_setaffinity",
"sched_setattr",
"sched_setparam",
"sched_setscheduler",
"sched_yield",
"seccomp",
"security",
"select",
"semctl",
"semget",
"semop",
"semtimedop",
"sendfile",
"sendmmsg",
"sendmsg",
"sendto",
"set_mempolicy",
"set_mempolicy_home_node",
"setdomainname",
"setfsgid",
"setfsuid",
"setgid",
"setgroups",
"sethostname",
"setitimer",
"setns",
"setpgid",
"setpriority",
"setregid",
"setresgid",
"setresuid",
"setreuid",
"setrlimit",
"setsid",
"setsockopt",
"settimeofday",
"setuid",
"shmat",
"shmctl",
"shmdt",
"shmget",
"shutdown",
"signalfd",
"signalfd4",
"socket",
"socketpair",
"splice",
"stat",
"statfs",
"statmount",
"statx",
"swapoff",
"swapon",
"sysfs",
"sysinfo",
"syslog",
"tee",
"tgkill",
"time",
"timer_create",
"timer_delete",
"timer_getoverrun",
"timer_gettime",
"timer_settime",
"timerfd_create",
"timerfd_gettime",
"timerfd_settime",
"times",
"tkill",
"tuxcall",
"umount2",
"uname",
"unshare",
"uselib",
"userfaultfd",
"ustat",
"utime",
"utimensat",
"utimes",
"vfork",
"vhangup",
"vmsplice",
"vserver",
"wait4",
"waitid",
"write",
"writev",
];
const PASSTHROUGH_SYSCALLS: &[&str] = &[
"access",
"brk",
"capget",
"capset",
"chdir",
"chmod",
"chroot",
"faccessat",
"faccessat2",
"fallocate",
"fchdir",
"fchmod",
"fchmodat",
"fchmodat2",
"fdatasync",
"fgetxattr",
"flistxattr",
"fremovexattr",
"fsetxattr",
"fsync",
"ftruncate",
"get_robust_list",
"get_thread_area",
"getcwd",
"getgroups",
"getpgid",
"getpgrp",
"getpid",
"getppid",
"getsid",
"gettid",
"getxattr",
"lgetxattr",
"link",
"linkat",
"listxattr",
"llistxattr",
"lremovexattr",
"lsetxattr",
"mkdir",
"mkdirat",
"mknod",
"mknodat",
"mlock",
"mlock2",
"mlockall",
"modify_ldt",
"mprotect",
"msync",
"munlock",
"munlockall",
"personality",
"pkey_alloc",
"pkey_free",
"pkey_mprotect",
"readahead",
"removexattr",
"rename",
"renameat",
"renameat2",
"rmdir",
"rt_sigreturn",
"sched_get_priority_max",
"sched_get_priority_min",
"set_robust_list",
"set_thread_area",
"set_tid_address",
"setxattr",
"sigaltstack",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"truncate",
"umask",
"unlink",
"unlinkat",
];
const UNSUPPORTED_SYSCALLS: &[&str] = &["restart_syscall"];
fn census_by_class(classify: impl Fn(Sysno) -> SyscallClassification) -> [Vec<String>; 3] {
let mut buckets: [Vec<String>; 3] = [Vec::new(), Vec::new(), Vec::new()];
for sysno in all_pinned_syscalls() {
let bucket = match classify(sysno) {
SyscallClassification::Determinized => 0,
SyscallClassification::PassThrough => 1,
SyscallClassification::Unsupported => 2,
};
buckets[bucket].push(sysno.to_string());
}
for bucket in buckets.iter_mut() {
bucket.sort();
}
buckets
}
fn census_mismatches(buckets: &[Vec<String>; 3]) -> Vec<String> {
let reviewed = [
DETERMINIZED_SYSCALLS,
PASSTHROUGH_SYSCALLS,
UNSUPPORTED_SYSCALLS,
];
let class_names = ["Determinized", "PassThrough", "Unsupported"];
let mut findings = Vec::new();
for index in 0..3 {
let actual: BTreeSet<&str> = buckets[index].iter().map(String::as_str).collect();
let want: BTreeSet<&str> = reviewed[index].iter().copied().collect();
for name in want.difference(&actual) {
findings.push(format!("{name}: left {}", class_names[index]));
}
for name in actual.difference(&want) {
findings.push(format!("{name}: entered {}", class_names[index]));
}
}
findings.sort();
findings
}
#[test]
fn every_pinned_sysno_has_an_explicit_classification() {
let buckets = census_by_class(classify_syscall);
let mismatches = census_mismatches(&buckets);
assert!(
mismatches.is_empty(),
"syscall classification differs from the reviewed membership. Update the \
lists deliberately, naming the policy change:\n {}",
mismatches.join("\n ")
);
let counted: usize = buckets.iter().map(Vec::len).sum();
assert_eq!(counted, EXPECTED_X86_64_SYSNO_COUNT);
let reviewed =
DETERMINIZED_SYSCALLS.len() + PASSTHROUGH_SYSCALLS.len() + UNSUPPORTED_SYSCALLS.len();
assert_eq!(reviewed, EXPECTED_X86_64_SYSNO_COUNT);
}
#[test]
fn census_refuses_a_moved_syscall() {
let perturbed = |sysno: Sysno| {
if sysno == Sysno::futex {
SyscallClassification::PassThrough
} else {
classify_syscall(sysno)
}
};
let findings = census_mismatches(&census_by_class(perturbed));
assert_eq!(
findings,
vec![
"futex: entered PassThrough".to_string(),
"futex: left Determinized".to_string(),
],
"the census must name the moved syscall and both directions"
);
}
#[test]
fn census_refuses_a_count_preserving_swap() {
let perturbed = |sysno: Sysno| match sysno {
Sysno::futex => SyscallClassification::PassThrough,
Sysno::get_robust_list => SyscallClassification::Determinized,
other => classify_syscall(other),
};
let buckets = census_by_class(perturbed);
assert_eq!(
[buckets[0].len(), buckets[1].len(), buckets[2].len()],
[
DETERMINIZED_SYSCALLS.len(),
PASSTHROUGH_SYSCALLS.len(),
UNSUPPORTED_SYSCALLS.len(),
],
"the planted swap must leave all three class sizes unchanged"
);
let findings = census_mismatches(&buckets);
assert_eq!(
findings,
vec![
"futex: entered PassThrough".to_string(),
"futex: left Determinized".to_string(),
"get_robust_list: entered Determinized".to_string(),
"get_robust_list: left PassThrough".to_string(),
]
);
}
#[test]
fn representative_policies_stay_in_their_reviewed_sections() {
assert_eq!(
classify_syscall(Sysno::futex),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::nanosleep),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::lseek),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::ppoll),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::select),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::pselect6),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::arch_prctl),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::prlimit64),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::pwrite64),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::madvise),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::mincore),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::writev),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::times),
SyscallClassification::Determinized
);
for sysno in [
Sysno::flock,
Sysno::ioprio_get,
Sysno::ioprio_set,
Sysno::sched_getattr,
Sysno::sched_setattr,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
for sysno in [Sysno::close_range, Sysno::seccomp, Sysno::sendfile] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
assert_eq!(
classify_syscall(Sysno::copy_file_range),
SyscallClassification::Determinized
);
for sysno in [Sysno::readlink, Sysno::readlinkat] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
assert_eq!(
classify_syscall(Sysno::recvmmsg),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::recvmsg),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::shutdown),
SyscallClassification::Determinized
);
assert_eq!(
classify_syscall(Sysno::seccomp),
SyscallClassification::Determinized
);
for sysno in [
Sysno::epoll_pwait2,
Sysno::clock_settime,
Sysno::getpeername,
Sysno::getsockname,
Sysno::getsockopt,
Sysno::getitimer,
Sysno::getpriority,
Sysno::getrlimit,
Sysno::kill,
Sysno::listen,
Sysno::prctl,
Sysno::rt_sigpending,
Sysno::setitimer,
Sysno::setpgid,
Sysno::setpriority,
Sysno::process_madvise,
Sysno::setrlimit,
Sysno::setsockopt,
Sysno::tgkill,
Sysno::readv,
Sysno::preadv,
Sysno::preadv2,
Sysno::pwritev,
Sysno::pwritev2,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
for sysno in [
Sysno::tkill,
Sysno::rt_sigqueueinfo,
Sysno::rt_tgsigqueueinfo,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
for sysno in [
Sysno::capget,
Sysno::capset,
Sysno::chdir,
Sysno::chmod,
Sysno::faccessat,
Sysno::faccessat2,
Sysno::fchdir,
Sysno::fchmod,
Sysno::fchmodat,
Sysno::fchmodat2,
Sysno::fdatasync,
Sysno::fallocate,
Sysno::fgetxattr,
Sysno::flistxattr,
Sysno::fremovexattr,
Sysno::fsetxattr,
Sysno::ftruncate,
Sysno::fsync,
Sysno::munlock,
Sysno::munlockall,
Sysno::rename,
Sysno::renameat,
Sysno::getgroups,
Sysno::getppid,
Sysno::getxattr,
Sysno::getpgid,
Sysno::getpgrp,
Sysno::getsid,
Sysno::lgetxattr,
Sysno::link,
Sysno::linkat,
Sysno::listxattr,
Sysno::llistxattr,
Sysno::lremovexattr,
Sysno::lsetxattr,
Sysno::mkdir,
Sysno::mkdirat,
Sysno::msync,
Sysno::removexattr,
Sysno::readahead,
Sysno::renameat2,
Sysno::rmdir,
Sysno::rt_sigreturn,
Sysno::setxattr,
Sysno::symlink,
Sysno::symlinkat,
Sysno::sync_file_range,
Sysno::truncate,
Sysno::umask,
Sysno::unlink,
Sysno::unlinkat,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::PassThrough);
}
for sysno in [Sysno::add_key, Sysno::keyctl, Sysno::request_key] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
assert!(is_kernel_keyring_syscall(sysno));
}
for sysno in [
Sysno::chroot,
Sysno::get_thread_area,
Sysno::mknod,
Sysno::mknodat,
Sysno::mlock,
Sysno::mlock2,
Sysno::mlockall,
Sysno::modify_ldt,
Sysno::personality,
Sysno::pkey_alloc,
Sysno::pkey_free,
Sysno::pkey_mprotect,
Sysno::sched_get_priority_max,
Sysno::sched_get_priority_min,
Sysno::set_thread_area,
Sysno::sync,
Sysno::syncfs,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::PassThrough);
}
for sysno in [
Sysno::mbind,
Sysno::set_mempolicy,
Sysno::get_mempolicy,
Sysno::set_mempolicy_home_node,
Sysno::migrate_pages,
Sysno::move_pages,
Sysno::sched_setscheduler,
Sysno::sched_setparam,
Sysno::sched_getscheduler,
Sysno::sched_getparam,
Sysno::sched_rr_get_interval,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
for sysno in [
Sysno::io_setup,
Sysno::io_destroy,
Sysno::io_submit,
Sysno::io_cancel,
Sysno::io_getevents,
Sysno::io_pgetevents,
Sysno::mq_open,
Sysno::mq_unlink,
Sysno::mq_timedsend,
Sysno::mq_timedreceive,
Sysno::mq_notify,
Sysno::mq_getsetattr,
Sysno::msgget,
Sysno::msgsnd,
Sysno::msgrcv,
Sysno::msgctl,
Sysno::semctl,
Sysno::semget,
Sysno::semop,
Sysno::semtimedop,
Sysno::shmat,
Sysno::shmctl,
Sysno::shmdt,
Sysno::shmget,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
assert!(is_unsupported_async_ipc_syscall(sysno));
}
}
#[test]
fn clock_discipline_and_kernel_log_syscalls_are_determinized() {
for sysno in [Sysno::adjtimex, Sysno::clock_adjtime, Sysno::syslog] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
}
#[test]
fn pidfd_family_is_determinized() {
for sysno in [
Sysno::pidfd_open,
Sysno::pidfd_getfd,
Sysno::pidfd_send_signal,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
}
}
#[test]
fn get_robust_list_is_a_reviewed_passthrough() {
assert_eq!(
classify_syscall(Sysno::get_robust_list),
SyscallClassification::PassThrough
);
assert_eq!(
classify_syscall(Sysno::set_robust_list),
SyscallClassification::PassThrough
);
}
#[test]
fn unimplemented_enosys_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::_sysctl,
Sysno::afs_syscall,
Sysno::create_module,
Sysno::get_kernel_syms,
Sysno::getpmsg,
Sysno::lookup_dcookie,
Sysno::nfsservctl,
Sysno::putpmsg,
Sysno::query_module,
Sysno::security,
Sysno::tuxcall,
Sysno::uselib,
Sysno::vserver,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_unimplemented_enosys_syscall(sysno),
"{sysno:?} should be in the ENOSYS-refusal helper set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
if is_unimplemented_enosys_syscall(sysno) {
assert!(
refused.contains(&sysno),
"{sysno:?} is flagged by the helper but not in the reviewed refusal set"
);
}
}
}
#[test]
fn futex2_syscalls_are_determinized_and_consistent() {
for sysno in [
Sysno::futex_requeue,
Sysno::futex_wait,
Sysno::futex_waitv,
Sysno::futex_wake,
] {
assert_eq!(classify_syscall(sysno), SyscallClassification::Determinized);
assert!(is_futex2_enosys_syscall(sysno));
}
assert!(!is_futex2_enosys_syscall(Sysno::futex));
}
#[test]
fn batch38_openat2_and_credential_syscalls_are_determinized() {
assert_eq!(
classify_syscall(Sysno::openat2),
SyscallClassification::Determinized,
"openat2 should be Determinized (deterministic ENOSYS fallback)"
);
let credentials = [
Sysno::setuid,
Sysno::setgid,
Sysno::setresuid,
Sysno::setresgid,
Sysno::setreuid,
Sysno::setregid,
Sysno::setgroups,
Sysno::setfsuid,
Sysno::setfsgid,
];
for sysno in credentials {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic no-op success)"
);
assert!(
is_credential_identity_noop_syscall(sysno),
"{sysno:?} should be in the credential no-op helper set"
);
}
let credential_queries = [
Sysno::getuid,
Sysno::geteuid,
Sysno::getgid,
Sysno::getegid,
Sysno::getresuid,
Sysno::getresgid,
];
for sysno in credential_queries {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (emulated virtual-root identity)"
);
assert!(
!is_credential_identity_noop_syscall(sysno),
"{sysno:?} is a credential query, not a credential-setting no-op"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
if is_credential_identity_noop_syscall(sysno) {
assert!(
credentials.contains(&sysno),
"{sysno:?} is flagged by the credential helper but not in the reviewed set"
);
assert!(!is_unimplemented_enosys_syscall(sysno));
assert!(!is_privileged_admin_refused_syscall(sysno));
assert!(!is_mount_ns_admin_refused_syscall(sysno));
assert!(!is_unsupported_async_ipc_syscall(sysno));
}
}
}
#[test]
fn landlock_sandbox_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::landlock_create_ruleset,
Sysno::landlock_add_rule,
Sysno::landlock_restrict_self,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_landlock_sandbox_syscall(sysno),
"{sysno:?} should be in the Landlock ENOSYS-refusal helper set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
if is_landlock_sandbox_syscall(sysno) {
assert!(
refused.contains(&sysno),
"{sysno:?} is flagged by the helper but not in the reviewed refusal set"
);
}
}
}
#[test]
fn mount_introspection_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::sysfs,
Sysno::statmount,
Sysno::listmount,
Sysno::ustat,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_mount_introspection_enosys_syscall(sysno),
"{sysno:?} should be in the mount-introspection refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_mount_introspection_enosys_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} mount-introspection helper membership is inconsistent"
);
}
}
#[test]
fn host_security_identity_probes_are_determinized_and_consistent() {
let refused = [Sysno::lsm_get_self_attr, Sysno::lsm_set_self_attr];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_host_security_identity_probe_syscall(sysno),
"{sysno:?} should be in the host security/identity refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_host_security_identity_probe_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} host security/identity helper membership is inconsistent"
);
}
}
#[test]
fn filesystem_handle_export_is_determinized() {
assert_eq!(
classify_syscall(Sysno::name_to_handle_at),
SyscallClassification::Determinized
);
}
#[test]
fn zero_copy_pipe_syscalls_are_determinized_and_consistent() {
let syscalls = [Sysno::splice, Sysno::tee, Sysno::vmsplice];
for sysno in syscalls {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized"
);
assert!(
is_zero_copy_pipe_syscall(sysno),
"{sysno:?} should be in the zero-copy pipe set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_zero_copy_pipe_syscall(sysno),
syscalls.contains(&sysno),
"{sysno:?} zero-copy pipe helper membership is inconsistent"
);
}
}
#[test]
fn kernel_keyring_syscalls_are_determinized_and_consistent() {
let refused = [Sysno::add_key, Sysno::request_key, Sysno::keyctl];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_kernel_keyring_syscall(sysno),
"{sysno:?} should be in the kernel-keyring refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_kernel_keyring_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} kernel-keyring helper membership is inconsistent"
);
}
}
#[test]
fn optional_memory_feature_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::memfd_secret,
Sysno::process_mrelease,
Sysno::map_shadow_stack,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic ENOSYS refusal)"
);
assert!(
is_optional_memory_feature_syscall(sysno),
"{sysno:?} should be in the optional-memory refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_optional_memory_feature_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} optional-memory helper membership is inconsistent"
);
}
}
#[test]
fn host_kernel_probe_syscalls_are_determinized_and_consistent() {
let probes = [Sysno::bpf, Sysno::cachestat, Sysno::lsm_list_modules];
for sysno in probes {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should use deterministic ENOSYS"
);
assert!(is_host_kernel_probe_syscall(sysno));
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_host_kernel_probe_syscall(sysno),
probes.contains(&sysno),
"{sysno:?} host-kernel probe membership is inconsistent"
);
}
}
#[test]
fn privileged_admin_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::init_module,
Sysno::finit_module,
Sysno::delete_module,
Sysno::kexec_load,
Sysno::kexec_file_load,
Sysno::reboot,
Sysno::swapon,
Sysno::swapoff,
Sysno::ioperm,
Sysno::iopl,
Sysno::pivot_root,
Sysno::sethostname,
Sysno::setdomainname,
Sysno::vhangup,
Sysno::quotactl,
Sysno::quotactl_fd,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic EPERM refusal)"
);
assert!(
is_privileged_admin_refused_syscall(sysno),
"{sysno:?} should be in the EPERM-refusal helper set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
if is_privileged_admin_refused_syscall(sysno) {
assert!(
refused.contains(&sysno),
"{sysno:?} is flagged by the helper but not in the reviewed refusal set"
);
}
}
}
#[test]
fn process_isolation_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::acct,
Sysno::process_vm_readv,
Sysno::process_vm_writev,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic EPERM refusal)"
);
assert!(
is_process_isolation_refused_syscall(sysno),
"{sysno:?} should be in the process-isolation refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_process_isolation_refused_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} process-isolation helper membership is inconsistent"
);
}
}
#[test]
fn privileged_observation_syscalls_are_determinized_and_consistent() {
let refused = [Sysno::ptrace, Sysno::kcmp];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic EPERM refusal)"
);
assert!(
is_privileged_observation_refused_syscall(sysno),
"{sysno:?} should be in the privileged-observation refusal set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_privileged_observation_refused_syscall(sysno),
refused.contains(&sysno),
"{sysno:?} privileged-observation helper membership is inconsistent"
);
}
}
#[test]
fn perf_event_open_is_deterministically_unavailable() {
assert_eq!(
classify_syscall(Sysno::perf_event_open),
SyscallClassification::Determinized
);
assert!(is_perf_event_enosys_syscall(Sysno::perf_event_open));
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_perf_event_enosys_syscall(sysno),
sysno == Sysno::perf_event_open,
"{sysno:?} perf-event helper membership is inconsistent"
);
}
}
#[test]
fn remap_file_pages_is_deterministically_unavailable() {
assert_eq!(
classify_syscall(Sysno::remap_file_pages),
SyscallClassification::Determinized
);
assert!(is_remap_file_pages_enosys_syscall(Sysno::remap_file_pages));
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
assert_eq!(
is_remap_file_pages_enosys_syscall(sysno),
sysno == Sysno::remap_file_pages,
"{sysno:?} remap-file-pages helper membership is inconsistent"
);
}
}
#[test]
fn mount_ns_admin_syscalls_are_determinized_and_consistent() {
let refused = [
Sysno::mount,
Sysno::umount2,
Sysno::mount_setattr,
Sysno::move_mount,
Sysno::open_tree,
Sysno::fsopen,
Sysno::fsmount,
Sysno::fsconfig,
Sysno::fspick,
Sysno::unshare,
Sysno::setns,
Sysno::open_by_handle_at,
Sysno::fanotify_init,
Sysno::fanotify_mark,
Sysno::settimeofday,
];
for sysno in refused {
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} should be Determinized (deterministic EPERM refusal)"
);
assert!(
is_mount_ns_admin_refused_syscall(sysno),
"{sysno:?} should be in the mount/namespace EPERM-refusal helper set"
);
}
for sysno in Sysno::iter().chain(std::iter::once(Sysno::last())) {
if is_mount_ns_admin_refused_syscall(sysno) {
assert!(
refused.contains(&sysno),
"{sysno:?} is flagged by the helper but not in the reviewed refusal set"
);
}
}
}
#[test]
fn deterministic_refusal_aggregate_includes_fixed_error_families() {
let refused_members = [
Sysno::rseq,
Sysno::perf_event_open,
Sysno::splice,
Sysno::tee,
Sysno::vmsplice,
Sysno::keyctl,
Sysno::add_key,
Sysno::request_key,
Sysno::landlock_create_ruleset,
Sysno::mount,
Sysno::remap_file_pages,
Sysno::name_to_handle_at,
Sysno::openat2,
Sysno::copy_file_range,
Sysno::clock_settime,
Sysno::futimesat,
Sysno::io_uring_setup,
Sysno::io_uring_enter,
Sysno::io_uring_register,
Sysno::epoll_ctl_old,
];
for sysno in refused_members {
assert!(
is_deterministically_refused_syscall(sysno),
"{sysno:?} should be in the deterministic-refusal aggregate"
);
}
let excluded = [
Sysno::setuid, Sysno::setgid, Sysno::timer_create, Sysno::bind, Sysno::read, Sysno::write, Sysno::getpid, ];
for sysno in excluded {
assert!(
!is_deterministically_refused_syscall(sysno),
"{sysno:?} must NOT be in the deterministic-refusal aggregate (it is emulated/forwarded)"
);
}
for sysno in [
Sysno::rseq,
Sysno::splice,
Sysno::tee,
Sysno::vmsplice,
Sysno::keyctl,
Sysno::add_key,
Sysno::request_key,
] {
assert!(is_strict_only_deterministic_refusal_syscall(sysno));
}
for sysno in [Sysno::openat2, Sysno::perf_event_open, Sysno::clock_settime] {
assert!(!is_strict_only_deterministic_refusal_syscall(sysno));
}
}
#[test]
fn ownership_change_family_is_determinized_not_passthrough() {
for sysno in [Sysno::chown, Sysno::fchown, Sysno::fchownat, Sysno::lchown] {
assert!(
is_ownership_change_noop_syscall(sysno),
"{sysno:?} must be in the ownership-change no-op set"
);
assert_eq!(
classify_syscall(sysno),
SyscallClassification::Determinized,
"{sysno:?} must be Determinized; PassThrough forwards it to a host \
identity that is not the virtual root Detcore reports"
);
}
for sysno in [
Sysno::chmod,
Sysno::fchmod,
Sysno::fchmodat,
Sysno::setuid,
Sysno::setgid,
Sysno::getuid,
] {
assert!(
!is_ownership_change_noop_syscall(sysno),
"{sysno:?} must NOT be in the ownership-change no-op set"
);
}
assert!(!is_credential_identity_noop_syscall(Sysno::chown));
assert!(!is_ownership_change_noop_syscall(Sysno::setuid));
}
}