seccomp/
syscall.rs

1//! Helper functions wrapper the seccomp crate.
2use super::raw;
3use crate::get_architecture;
4use nix::libc::free;
5use std::{
6    error,
7    ffi::{CStr, CString, c_int, c_void},
8    fmt,
9};
10
11/// An error trying to resolve a syscall, either from string to number, or number to string.
12#[derive(Debug)]
13pub enum Error {
14    Name(String),
15    Code(c_int),
16}
17impl fmt::Display for Error {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            Error::Name(name) => write!(f, "Failed to resolve syscall name: {name}"),
21            Error::Code(code) => write!(f, "Failed to resolve syscall name: {code}"),
22        }
23    }
24}
25impl error::Error for Error {}
26
27/// A Syscall, which can be constructed from either the number, or from the name.
28#[derive(Debug, Copy, Clone)]
29pub struct Syscall {
30    /// The architecture specific code.
31    code: c_int,
32}
33impl Syscall {
34    /// Construct a Syscall from the number. No validation is performed.
35    pub fn from_number(code: c_int) -> Self {
36        Self { code }
37    }
38
39    /// Construct a Syscall from a name, returning Error if libseccomp could not resolve the name.
40    pub fn from_name(name: &str) -> Result<Self, Error> {
41        if let Ok(c_name) = CString::new(name) {
42            match unsafe { raw::seccomp_syscall_resolve_name(c_name.as_ptr()) } {
43                -1 => Err(Error::Name(name.to_string())),
44                code => Ok(Self { code }),
45            }
46        } else {
47            Err(Error::Name(name.to_string()))
48        }
49    }
50
51    /// Resolve a name to a syscall number for a specific architecture.
52    /// Fails if libseccomp could not resolve the name.
53    pub fn with_arch(name: &str, arch: u32) -> Result<Self, Error> {
54        if let Ok(c_name) = CString::new(name) {
55            match unsafe { raw::seccomp_syscall_resolve_name_arch(arch, c_name.as_ptr()) } {
56                -1 => Err(Error::Name(name.to_string())),
57                code => Ok(Self { code }),
58            }
59        } else {
60            Err(Error::Name(name.to_string()))
61        }
62    }
63
64    /// Get the name for a syscall on the native architecture.
65    pub fn get_name(num: c_int) -> Result<String, Error> {
66        Self::get_name_arch(num, get_architecture())
67    }
68
69    /// Get the name for a syscall on the provided architecture.
70    pub fn get_name_arch(num: c_int, arch: u32) -> Result<String, Error> {
71        let name = unsafe { raw::seccomp_syscall_resolve_num_arch(arch, num) };
72
73        if name.is_null() {
74            Err(Error::Code(num))
75        } else {
76            let syscall_name = unsafe {
77                let c_str = CStr::from_ptr(name);
78                if let Ok(result) = c_str.to_str() {
79                    let result = result.to_owned();
80                    free(name as *mut c_void);
81                    result
82                } else {
83                    return Err(Error::Code(num));
84                }
85            };
86            Ok(syscall_name)
87        }
88    }
89
90    /// Get the numerical value of the syscall.
91    pub fn get_number(&self) -> i32 {
92        self.code
93    }
94}
95impl From<Syscall> for c_int {
96    fn from(syscall: Syscall) -> c_int {
97        syscall.code
98    }
99}
100impl fmt::Display for Syscall {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "{}", self.code)
103    }
104}