use crate::page_size;
use anyhow::Result;
use std::io::Error;
pub const PROT_NONE: u32 = libc::PROT_NONE as u32;
pub fn pkey_alloc(flags: u32, access_rights: u32) -> Result<u32> {
assert_eq!(flags, 0); let result = unsafe { libc::syscall(libc::SYS_pkey_alloc, flags, access_rights) };
if result >= 0 {
Ok(result
.try_into()
.expect("only pkey IDs between 0 and 15 are expected"))
} else {
debug_assert_eq!(result, -1); Err(Error::last_os_error().into())
}
}
#[allow(dead_code)]
pub fn pkey_free(key: u32) -> Result<()> {
let result = unsafe { libc::syscall(libc::SYS_pkey_free, key) };
if result == 0 {
Ok(())
} else {
debug_assert_eq!(result, -1); Err(Error::last_os_error().into())
}
}
pub fn pkey_mprotect(addr: usize, len: usize, prot: u32, key: u32) -> Result<()> {
let page_size = page_size();
if addr % page_size != 0 {
log::warn!(
"memory must be page-aligned for MPK (addr = {addr:#x}, page size = {page_size}"
);
}
let result = unsafe { libc::syscall(libc::SYS_pkey_mprotect, addr, len, prot, key) };
if result == 0 {
Ok(())
} else {
debug_assert_eq!(result, -1); Err(Error::last_os_error().into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[ignore = "cannot be run when keys() has already allocated all keys"]
#[test]
fn check_allocate_and_free() {
let key = pkey_alloc(0, 0).unwrap();
assert_eq!(key, 1);
pkey_free(key).unwrap()
}
#[test]
fn check_invalid_free() {
let result = pkey_free(42);
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Invalid argument (os error 22)"
);
}
#[test]
#[should_panic]
fn check_invalid_alloc_flags() {
let _ = pkey_alloc(42, 0);
}
#[test]
fn check_invalid_alloc_rights() {
assert!(pkey_alloc(0, 42).is_err());
}
}