use std::ffi::{c_char, CString};
extern "C" {
fn sandbox_init(profile: *const c_char, flags: u64, error: *mut *mut c_char) -> i32;
fn sandbox_free_error(error: *mut c_char);
fn strlen(text: *const c_char) -> usize;
}
const PROFILE_IS_LITERAL: u64 = 0;
pub fn apply(profile: &str) -> anyhow::Result<()> {
let text = CString::new(profile)
.map_err(|_| anyhow::anyhow!("the sandbox profile contains a NUL byte"))?;
let mut error: *mut c_char = std::ptr::null_mut();
let code = unsafe { sandbox_init(text.as_ptr(), PROFILE_IS_LITERAL, &mut error) };
if code == 0 {
if !error.is_null() {
unsafe { sandbox_free_error(error) };
}
return Ok(());
}
let detail = read_error(error);
anyhow::bail!(
"the kernel refused the sandbox profile: {detail}. Nothing was applied, \
so the command was not started."
)
}
fn read_error(error: *mut c_char) -> String {
if error.is_null() {
return "no reason given".to_string();
}
let length = unsafe { strlen(error) };
let bytes = unsafe { std::slice::from_raw_parts(error as *const u8, length) };
let detail = String::from_utf8_lossy(bytes).into_owned();
unsafe { sandbox_free_error(error) };
detail
}
pub fn available() -> bool {
true
}