pub mod errors;
mod rseal;
use std::{
alloc::{alloc, Layout},
fmt,
marker::PhantomData,
ptr::NonNull,
};
use errors::RSealMemError;
use rseal::seal_memory;
pub struct RSealBuff {
region: RSealMemory<u8>,
}
impl RSealBuff {
pub fn new(size: usize) -> Result<Self, RSealMemError> {
Ok(Self {
region: RSealMemory::new(size)?,
})
}
pub fn write(&mut self, data: &[u8]) -> usize {
let buf = unsafe { self.region.as_mut() };
let len = std::cmp::min(buf.len(), data.len());
buf[..len].copy_from_slice(&data[..len]);
len
}
pub fn read(&self) -> &[u8] {
unsafe { self.region.as_ref() }
}
}
struct RSealMemory<T> {
ptr: NonNull<T>,
layout: Layout,
_phantom: PhantomData<T>,
}
impl fmt::Display for RSealMemError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AllocationError => write!(f, "Allocation error"),
Self::SealError(e) => write!(f, "Sealing error: {}", e),
Self::InvalidParameters(msg) => write!(f, "Invalid parameters: {}", msg),
}
}
}
impl<T> RSealMemory<T> {
fn new(count: usize) -> Result<Self, RSealMemError> {
let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) } as usize;
let item_size = std::mem::size_of::<T>();
let requested_size = item_size * count;
let total_size = (requested_size + page_size - 1) & !(page_size - 1);
let layout = Layout::from_size_align(total_size, page_size)
.map_err(|_| RSealMemError::InvalidParameters("Invalid size or alignment"))?;
let ptr = unsafe { NonNull::new(alloc(layout) as *mut T) }
.ok_or(RSealMemError::AllocationError)?;
unsafe {
seal_memory(ptr.as_ptr() as *mut libc::c_void, total_size, 0)
.map_err(RSealMemError::SealError)?;
}
Ok(Self {
ptr,
layout,
_phantom: PhantomData,
})
}
fn len(&self) -> usize {
self.layout.size() / std::mem::size_of::<T>()
}
unsafe fn as_ref(&self) -> &[T] {
std::slice::from_raw_parts(self.ptr.as_ptr(), self.len())
}
unsafe fn as_mut(&mut self) -> &mut [T] {
std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len())
}
}
impl<T> Drop for RSealMemory<T> {
fn drop(&mut self) {
eprintln!("Warning: Dropping sealed memory region - this memory will remain allocated until process termination");
}
}
#[cfg(test)]
mod tests {
use errors::RSealError;
use super::*;
#[test]
fn test_sealed_buffer() {
let result = RSealBuff::new(4096);
if let Err(RSealMemError::SealError(RSealError::SyscallNotImplemented(_))) = result {
eprintln!("Skipping test_sealed_buffer: mseal syscall not implemented");
return;
}
let mut buffer = result.unwrap();
let data = b"Hello, world!";
let written = buffer.write(data);
assert_eq!(written, data.len());
assert_eq!(&buffer.read()[..written], data);
}
#[test]
fn test_sealed_memory() {
let result = RSealMemory::<u32>::new(1024);
if let Err(RSealMemError::SealError(RSealError::SyscallNotImplemented(_))) = result {
eprintln!("Skipping test_sealed_memory: mseal syscall not implemented");
return;
}
assert!(result.is_ok());
}
}