sandlock_core/seccomp/
syscall.rs1use thiserror::Error;
8
9#[derive(Debug, Error, PartialEq, Eq)]
10pub enum SyscallError {
11 #[error("syscall number {0} is negative")]
12 Negative(i64),
13 #[error("syscall number {0} is unknown for the current architecture")]
14 UnknownForArch(i64),
15}
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
18pub struct Syscall(i64);
19
20impl Syscall {
21 pub fn checked(nr: i64) -> Result<Self, SyscallError> {
23 if nr < 0 {
24 return Err(SyscallError::Negative(nr));
25 }
26 if !crate::arch::is_known_syscall(nr) {
27 return Err(SyscallError::UnknownForArch(nr));
28 }
29 Ok(Self(nr))
30 }
31
32 pub fn raw(self) -> i64 {
33 self.0
34 }
35}
36
37impl TryFrom<i64> for Syscall {
38 type Error = SyscallError;
39 fn try_from(nr: i64) -> Result<Self, Self::Error> {
40 Self::checked(nr)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn checked_accepts_valid_openat() {
50 let s = Syscall::checked(libc::SYS_openat).expect("openat is valid");
51 assert_eq!(s.raw(), libc::SYS_openat);
52 }
53
54 #[test]
55 fn checked_rejects_negative() {
56 match Syscall::checked(-5) {
57 Err(SyscallError::Negative(-5)) => {}
58 other => panic!("expected Negative(-5), got {:?}", other),
59 }
60 }
61
62 #[test]
63 fn checked_rejects_arch_unknown() {
64 match Syscall::checked(99_999) {
66 Err(SyscallError::UnknownForArch(99_999)) => {}
67 other => panic!("expected UnknownForArch(99_999), got {:?}", other),
68 }
69 }
70
71 #[test]
72 fn try_from_i64_delegates_to_checked() {
73 let s: Syscall = libc::SYS_openat.try_into().expect("openat valid");
74 assert_eq!(s.raw(), libc::SYS_openat);
75 let bad: Result<Syscall, _> = (-1i64).try_into();
76 assert!(matches!(bad, Err(SyscallError::Negative(-1))));
77 }
78}