use std::ffi::{CString, c_char};
use std::path::Path;
unsafe extern "C" {
fn pledge(promises: *const c_char, execpromises: *const c_char) -> i32;
fn unveil(path: *const c_char, permissions: *const c_char) -> i32;
}
const VALID_PROMISES: &[&str] = &[
"audio",
"bpf",
"chown",
"cpath",
"disklabel",
"dns",
"dpath",
"drm",
"error",
"exec",
"fattr",
"flock",
"getpw",
"id",
"inet",
"mcast",
"pf",
"proc",
"prot_exec",
"ps",
"recvfd",
"route",
"rpath",
"sendfd",
"settime",
"stdio",
"tape",
"tmppath",
"tty",
"unix",
"unveil",
"video",
"vminfo",
"vmm",
"wpath",
"wroute",
];
const VALID_PERMS: &[u8] = b"rwcx";
pub fn do_pledge(promises: &str) {
for word in promises.split_whitespace() {
if !VALID_PROMISES.contains(&word) {
log::error!("pledge: unknown promise: {word}");
std::process::exit(1);
}
}
let c = CString::new(promises).unwrap_or_else(|_| {
log::error!("pledge: promises contain NUL byte");
std::process::exit(1);
});
let ret = unsafe { pledge(c.as_ptr(), std::ptr::null()) };
if ret != 0 {
let err = std::io::Error::last_os_error();
log::error!("pledge failed: {err}");
std::process::exit(1);
}
log::debug!("pledge applied");
}
pub fn do_unveil(path: &Path, perms: &str) {
if perms.is_empty()
|| !perms.as_bytes().iter().all(|b| VALID_PERMS.contains(b))
{
log::error!("unveil: invalid permissions");
std::process::exit(1);
}
let p = CString::new(path.as_os_str().as_encoded_bytes()).unwrap_or_else(
|_| {
log::error!("unveil: path contains NUL byte");
std::process::exit(1);
},
);
let f = CString::new(perms).unwrap_or_else(|_| {
log::error!("unveil: permissions contain NUL byte");
std::process::exit(1);
});
let ret = unsafe { unveil(p.as_ptr(), f.as_ptr()) };
if ret != 0 {
let err = std::io::Error::last_os_error();
log::error!("unveil failed: {err}");
std::process::exit(1);
}
log::debug!("unveil: path added");
}
pub fn unveil_lock() {
let ret = unsafe { unveil(std::ptr::null(), std::ptr::null()) };
if ret != 0 {
let err = std::io::Error::last_os_error();
log::error!("unveil lock failed: {err}");
std::process::exit(1);
}
log::debug!("unveil locked");
}