use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use crate::utils;
#[derive(Debug)]
pub struct SecBox<T> {
ptr: *mut T,
}
impl<T> SecBox<T> {
#[must_use]
#[inline]
pub fn new(val: T) -> SecBox<T> {
Self::try_new(val).expect("SecBox memory allocation failed!")
}
#[must_use]
#[inline]
pub fn construct<F: Fn() -> T>(f: F) -> SecBox<T> {
Self::try_construct(f).expect("SecBox memory allocation failed!")
}
#[must_use]
pub fn try_new(val: T) -> Option<SecBox<T>> {
if size_of::<T>() > *utils::PAGE_SIZE {
return None;
}
let region = utils::alloc(*utils::PAGE_SIZE)?;
let ptr = unsafe {
utils::memzero(region.as_ptr(), *utils::PAGE_SIZE);
let region = region.as_ptr() as *mut T;
region.write_unaligned(val);
utils::mlock(region.cast(), *utils::PAGE_SIZE);
utils::mprotect(region.cast(), *utils::PAGE_SIZE, utils::Prot::NoAccess);
region
};
Some(Self { ptr })
}
#[must_use]
pub fn try_construct<F: Fn() -> T>(f: F) -> Option<SecBox<T>> {
if size_of::<T>() > *utils::PAGE_SIZE {
return None;
}
let region = utils::alloc(*utils::PAGE_SIZE)?;
let ptr = unsafe {
utils::memzero(region.as_ptr(), *utils::PAGE_SIZE);
let region = region.as_ptr() as *mut T;
*region = f();
utils::mlock(region.cast(), *utils::PAGE_SIZE);
utils::mprotect(region.cast(), *utils::PAGE_SIZE, utils::Prot::NoAccess);
region
};
Some(Self { ptr })
}
#[must_use]
pub fn unlock(self) -> InsecBox<T> {
let u = ManuallyDrop::new(self);
unsafe {
utils::mprotect(u.ptr.cast(), *utils::PAGE_SIZE, utils::Prot::ReadWrite);
}
InsecBox { ptr: u.ptr }
}
#[must_use]
pub fn secure(s: InsecBox<T>) -> SecBox<T> {
let s = ManuallyDrop::new(s);
unsafe {
utils::mprotect(s.ptr.cast(), *utils::PAGE_SIZE, utils::Prot::NoAccess);
}
SecBox { ptr: s.ptr }
}
}
impl<T> Drop for SecBox<T> {
fn drop(&mut self) {
let region = self.ptr as *mut u8;
unsafe {
utils::mprotect(region, *utils::PAGE_SIZE, utils::Prot::ReadWrite);
utils::munlock(region, *utils::PAGE_SIZE);
utils::memzero(region, *utils::PAGE_SIZE);
utils::free(region, *utils::PAGE_SIZE);
}
}
}
#[derive(Debug)]
pub struct InsecBox<T> {
ptr: *mut T,
}
impl<T> Drop for InsecBox<T> {
fn drop(&mut self) {
let region = self.ptr as *mut u8;
unsafe {
utils::munlock(region, *utils::PAGE_SIZE);
utils::memzero(region, *utils::PAGE_SIZE);
utils::free(region, *utils::PAGE_SIZE);
}
}
}
impl<T> Deref for InsecBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
impl<T> DerefMut for InsecBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr }
}
}
impl<T> AsRef<T> for InsecBox<T>
where
<InsecBox<T> as Deref>::Target: AsRef<T>,
{
fn as_ref(&self) -> &T {
self.deref().as_ref()
}
}
impl<T> AsMut<T> for InsecBox<T>
where
<InsecBox<T> as Deref>::Target: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
self.deref_mut().as_mut()
}
}
impl<T> std::borrow::Borrow<T> for InsecBox<T> {
fn borrow(&self) -> &T {
&**self
}
}
impl<T> std::borrow::BorrowMut<T> for InsecBox<T> {
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
}