use crate::orchestration::SandboxProfile;
use crate::stdlib::sandbox::{
sandbox_rejection, SandboxMechanism, SandboxMechanismAvailability, SandboxMechanismUnavailable,
};
use crate::value::VmError;
const CS_OPS_STATUS: libc::c_uint = 0;
const CS_OPS_MARKRESTRICT: libc::c_uint = 8;
const CS_RESTRICT: u32 = 0x0000_0800;
const CSR_ALLOW_UNRESTRICTED_DTRACE: u32 = 0x0020;
pub(super) fn available() -> bool {
let mut development: libc::c_int = -1;
let mut size = std::mem::size_of_val(&development);
let mut integrity_config: u32 = 0;
(unsafe {
libc::sysctlbyname(
c"kern.development".as_ptr(),
(&raw mut development).cast(),
&raw mut size,
std::ptr::null_mut(),
0,
)
}) == 0
&& size == std::mem::size_of_val(&development)
&& unsafe { csr_get_active_config(&raw mut integrity_config) } == 0
&& supported_configuration(development, integrity_config)
}
fn supported_configuration(development: libc::c_int, integrity_config: u32) -> bool {
development == 0 && integrity_config & CSR_ALLOW_UNRESTRICTED_DTRACE == 0
}
pub(super) fn protect(profile: SandboxProfile) -> Result<(), VmError> {
if !available() {
return Err(SandboxMechanismUnavailable::new(
SandboxMechanism::MacosSandboxExec,
SandboxMechanismAvailability::AbsentOnHost,
profile,
)
.into_error());
}
if unsafe { csops(0, CS_OPS_MARKRESTRICT, std::ptr::null_mut(), 0) } != 0 {
return Err(sandbox_rejection(format!(
"macOS could not protect the host environment before starting a confined child: {}",
std::io::Error::last_os_error()
)));
}
let mut flags: u32 = 0;
if unsafe {
csops(
0,
CS_OPS_STATUS,
(&raw mut flags).cast(),
std::mem::size_of::<u32>(),
)
} != 0
|| flags & CS_RESTRICT == 0
{
return Err(sandbox_rejection(
"macOS did not confirm the host environment restriction; the child was not started"
.to_string(),
));
}
Ok(())
}
unsafe extern "C" {
fn csr_get_active_config(config: *mut u32) -> libc::c_int;
fn csops(
pid: libc::pid_t,
operation: libc::c_uint,
address: *mut libc::c_void,
size: libc::size_t,
) -> libc::c_int;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kernel_configuration_must_hold_the_parent_environment_boundary() {
assert!(supported_configuration(0, 0));
assert!(supported_configuration(0, 0x10));
assert!(!supported_configuration(-1, 0));
assert!(!supported_configuration(1, 0));
assert!(!supported_configuration(0, CSR_ALLOW_UNRESTRICTED_DTRACE));
}
}