use std::slice;
use libc::c_void;
#[cfg(cryptsetup23supported)]
use crate::Result;
macro_rules! define_handle {
($(#[$docs:meta])* $name:ident, $(#[$from_ptr_docs:meta])* from_ptr $(, $drop:expr)?) => {
$(#[$docs])*
#[cfg(cryptsetup23supported)]
pub struct $name(*mut c_void, usize);
#[cfg(cryptsetup23supported)]
impl $name {
$(#[$from_ptr_docs])*
pub unsafe fn from_ptr(ptr: *mut c_void, size: usize) -> Self {
$name(ptr, size)
}
}
#[cfg(cryptsetup23supported)]
impl Drop for $name {
fn drop(&mut self) {
self.safe_memzero();
$(
unsafe { $drop(self) };
)?
}
}
};
}
macro_rules! memzero {
($name:ident) => {
#[cfg(cryptsetup23supported)]
impl SafeMemzero for $name {
fn safe_memzero(&mut self) {
mutex!(libcryptsetup_rs_sys::crypt_safe_memzero(self.0, self.1))
}
}
};
}
macro_rules! as_ref {
($name:ident) => {
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.0 as *const _ as *const u8, self.1) }
}
}
impl AsMut<[u8]> for $name {
fn as_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.0 as *mut u8, self.1) }
}
}
};
}
#[cfg(cryptsetup23supported)]
pub trait SafeMemzero {
fn safe_memzero(&mut self);
}
define_handle! {
SafeOwnedMemZero,
from_ptr,
|self_: &mut SafeOwnedMemZero| {
libc::free(self_.0);
}
}
memzero!(SafeOwnedMemZero);
#[cfg(cryptsetup23supported)]
as_ref!(SafeOwnedMemZero);
define_handle! {
SafeBorrowedMemZero,
from_ptr
}
memzero!(SafeBorrowedMemZero);
#[cfg(cryptsetup23supported)]
as_ref!(SafeBorrowedMemZero);
pub struct SafeMemHandle(*mut c_void, usize);
impl SafeMemHandle {
pub(crate) unsafe fn from_ptr(ptr: *mut c_void, size: usize) -> Self {
SafeMemHandle(ptr, size)
}
#[cfg(cryptsetup23supported)]
pub fn alloc(size: usize) -> Result<Self> {
let ptr = ptr_to_result!(mutex!(libcryptsetup_rs_sys::crypt_safe_alloc(size)))?;
Ok(SafeMemHandle(ptr, size))
}
}
unsafe impl Send for SafeMemHandle {}
impl Drop for SafeMemHandle {
fn drop(&mut self) {
mutex!(libcryptsetup_rs_sys::crypt_safe_free(self.0))
}
}
memzero!(SafeMemHandle);
as_ref!(SafeMemHandle);
#[cfg(all(test, cryptsetup23supported, feature = "mutex"))]
mod test {
use super::*;
use std::io::Write;
#[test]
fn test_memzero() {
let mut handle = SafeMemHandle::alloc(32).unwrap();
handle.as_mut().write_all(&[20; 32]).unwrap();
assert_eq!(&[20; 32], handle.as_ref());
handle.safe_memzero();
assert_eq!(&[0; 32], handle.as_ref());
}
#[test]
fn test_memzero_borrowed() {
let mut slice = [0u8; 32];
let mut borrowed_handle =
unsafe { SafeBorrowedMemZero::from_ptr(slice.as_mut_ptr() as *mut _, slice.len()) };
borrowed_handle.as_mut().write_all(&[33; 32]).unwrap();
assert_eq!(&[33; 32], borrowed_handle.as_ref());
std::mem::drop(borrowed_handle);
assert_eq!(&[0u8; 32], &slice);
}
}