1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use crate::alloc::Sensitive;
use crate::pages::{Protection, page_align, protect, zero};
use crate::guard::{Guard, Protectable};

use std::io::Error;

type InnerBox<T> = std::boxed::Box<T, Sensitive>;
type Box<T> = Guard<InnerBox<T>>;

unsafe fn box_raw_ptr<T>(boxed: &InnerBox<T>) -> *mut u8 {
	debug_assert!(std::mem::size_of::<T>() > 0);

	(&**boxed as *const T).cast::<u8>() as *mut u8
}

fn box_protect<T>(boxed: &InnerBox<T>, prot: Protection) -> Result<(), std::io::Error> {
	if std::mem::size_of::<T>() > 0 {
		unsafe { protect(box_raw_ptr(boxed), page_align(std::mem::size_of::<T>()), prot) }
	} else {
		Ok(())
	}
}

impl<T> Protectable for InnerBox<T> {
	fn lock(&self) -> Result<(), Error> {
		box_protect(self, Protection::NoAccess)
	}

	fn unlock(&self) -> Result<(), Error> {
		box_protect(self, Protection::ReadOnly)
	}

	fn unlock_mut(&mut self) -> Result<(), Error> {
		box_protect(self, Protection::ReadWrite)
	}
}

impl<T> Box<T> {
	pub unsafe fn raw_ptr(&self) -> *mut u8 {
		box_raw_ptr(self.inner())
	}

	fn new_without_clear(source: T) -> Self {
		let mut guard = Guard::from_inner(std::boxed::Box::new_in(source, Sensitive));
		guard.mutate(|boxed| boxed.lock().unwrap());
		guard
	}

	pub fn new(mut source: T) -> Self {
		let ptr: *mut T = &mut source;
		let guard = Self::new_without_clear(source);

		// Clear out source
		unsafe { zero(ptr, 1); }

		guard
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	#[cfg(unix)]
	#[test]
	fn test_protection() {
		use bulletproof::Bulletproof;

		let mut test = Box::<u32>::new(0x55555555);
		let bp = unsafe { Bulletproof::new() };

		let ptr = unsafe { test.raw_ptr() };

		assert_eq!(unsafe { bp.load(ptr) }, Err(()));

		{
			let immutable = test.borrow();
			assert_eq!(*immutable, 0x55555555);
			assert_eq!(unsafe { bp.store(ptr, &0x55) }, Err(()));
		}

		assert_eq!(unsafe { bp.load(ptr) }, Err(()));

		{
			let mut mutable = test.borrow_mut();
			assert_eq!(*mutable, 0x55555555);
			*mutable = 0xdeadbeef;
			assert_eq!(*mutable, 0xdeadbeef);
		}

		assert_eq!(unsafe { bp.load(ptr) }, Err(()));
	}
}