1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::ffi::{CString, NulError};
use std::fmt;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::ptr;

// TODO: unveil!(path)
// This should either give all permissions or no permissions for the specified path.
#[macro_export]
macro_rules! unveil {
    () => {
        crate::unveil::disable()
    };
    ($path:expr, $perm:expr $(,)?) => {
        crate::unveil::unveil($path, $perm)
    };
}

pub fn unveil(path: impl AsRef<Path>, permissions: impl Into<Vec<u8>>) -> Result<(), Error> {
    let path = CString::new(path.as_ref().as_os_str().as_bytes())?;
    let permissions = CString::new(permissions)?;
    match unsafe { crate::ffi::unveil(path.as_ptr(), permissions.as_ptr()) } {
        0 => Ok(()),
        _ => Err(get_error()),
    }
}

pub fn disable() {
    assert_eq!(unsafe { crate::ffi::unveil(ptr::null(), ptr::null()) }, 0);
}

fn get_error() -> Error {
    match io::Error::last_os_error().raw_os_error() {
        Some(1) => Error::EPERM,
        Some(2) => Error::ENOENT,
        Some(7) => Error::E2BIG,
        Some(22) => Error::EINVAL,
        e => unreachable!("Unexpected errno: {:?}", e),
    }
}

// TODO: Give these better names.
#[derive(Debug, Clone)]
pub enum Error {
    NUL(NulError),
    EPERM,
    ENOENT,
    E2BIG,
    EINVAL,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NUL(e) => write!(f, "{}", e),
            Self::EPERM => write!(f, "An attempt to increase permissions was made, or the path was not accessible, or unveil() was called after locking."),
            Self::ENOENT => write!(f, "A directory in path did not exist."),
            Self::E2BIG => write!(f, "The addition of path would exceed the per-process limit for unveiled paths."),
            Self::EINVAL => write!(f, "An invalid value of permissions was used."),
        }
    }
}

impl std::error::Error for Error {}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Self::NUL(e)
    }
}