1use std::slice;
6
7use libc::c_void;
8
9#[cfg(cryptsetup23supported)]
10use crate::Result;
11
12macro_rules! define_handle {
13 ($(#[$docs:meta])* $name:ident, $(#[$from_ptr_docs:meta])* from_ptr $(, $drop:expr)?) => {
14 $(#[$docs])*
15 #[cfg(cryptsetup23supported)]
16 pub struct $name(*mut c_void, usize);
17
18 #[cfg(cryptsetup23supported)]
19 impl $name {
20 $(#[$from_ptr_docs])*
21 pub unsafe fn from_ptr(ptr: *mut c_void, size: usize) -> Self {
22 $name(ptr, size)
23 }
24 }
25
26 #[cfg(cryptsetup23supported)]
27 impl Drop for $name {
28 fn drop(&mut self) {
29 self.safe_memzero();
30 $(
31 #[allow(clippy::redundant_closure_call)]
32 unsafe { $drop(self) };
33 )?
34 }
35 }
36 };
37}
38
39macro_rules! memzero {
40 ($name:ident) => {
41 #[cfg(cryptsetup23supported)]
42 impl SafeMemzero for $name {
43 fn safe_memzero(&mut self) {
44 mutex!(libcryptsetup_rs_sys::crypt_safe_memzero(self.0, self.1))
45 }
46 }
47 };
48}
49
50macro_rules! as_ref {
51 ($name:ident) => {
52 impl AsRef<[u8]> for $name {
53 fn as_ref(&self) -> &[u8] {
54 unsafe { slice::from_raw_parts(self.0.cast::<u8>(), self.1) }
55 }
56 }
57
58 impl AsMut<[u8]> for $name {
59 fn as_mut(&mut self) -> &mut [u8] {
60 unsafe { slice::from_raw_parts_mut(self.0.cast::<u8>(), self.1) }
61 }
62 }
63 };
64}
65
66#[cfg(cryptsetup23supported)]
69pub trait SafeMemzero {
70 fn safe_memzero(&mut self);
73}
74
75define_handle! {
76 SafeOwnedMemZero,
88 from_ptr,
97 |self_: &mut SafeOwnedMemZero| {
98 libc::free(self_.0);
99 }
100}
101memzero!(SafeOwnedMemZero);
102#[cfg(cryptsetup23supported)]
103as_ref!(SafeOwnedMemZero);
104
105define_handle! {
106 SafeBorrowedMemZero,
112 from_ptr
119}
120memzero!(SafeBorrowedMemZero);
121#[cfg(cryptsetup23supported)]
122as_ref!(SafeBorrowedMemZero);
123
124pub struct SafeMemHandle(*mut c_void, usize);
126
127impl SafeMemHandle {
128 pub(crate) unsafe fn from_ptr(ptr: *mut c_void, size: usize) -> Self {
129 SafeMemHandle(ptr, size)
130 }
131
132 #[cfg(cryptsetup23supported)]
135 pub fn alloc(size: usize) -> Result<Self> {
136 let ptr = ptr_to_result!(mutex!(libcryptsetup_rs_sys::crypt_safe_alloc(size)))?;
137 Ok(SafeMemHandle(ptr, size))
138 }
139}
140
141unsafe impl Send for SafeMemHandle {}
144
145impl Drop for SafeMemHandle {
146 fn drop(&mut self) {
147 mutex!(libcryptsetup_rs_sys::crypt_safe_free(self.0))
148 }
149}
150memzero!(SafeMemHandle);
151as_ref!(SafeMemHandle);
152
153#[cfg(all(test, cryptsetup23supported, feature = "mutex"))]
154mod test {
155 use super::*;
156
157 use std::io::Write;
158
159 #[test]
160 fn test_memzero() {
161 let mut handle = SafeMemHandle::alloc(32).unwrap();
162 handle.as_mut().write_all(&[20; 32]).unwrap();
163 assert_eq!(&[20; 32], handle.as_ref());
164 handle.safe_memzero();
165 assert_eq!(&[0; 32], handle.as_ref());
166 }
167
168 #[test]
169 fn test_memzero_borrowed() {
170 let mut slice = [0u8; 32];
171 let mut borrowed_handle =
172 unsafe { SafeBorrowedMemZero::from_ptr(slice.as_mut_ptr().cast(), slice.len()) };
173 borrowed_handle.as_mut().write_all(&[33; 32]).unwrap();
174 assert_eq!(&[33; 32], borrowed_handle.as_ref());
175 std::mem::drop(borrowed_handle);
176 assert_eq!(&[0u8; 32], &slice);
177 }
178}