1use crate::error::{Result, SubstrateError};
2use libc::{c_void, mmap, mprotect, munmap, sysconf, MAP_ANON, MAP_FAILED, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE, _SC_PAGESIZE};
3use std::ptr;
4
5pub struct ProtectedMemory {
6 address: *mut u8,
7 width: usize,
8}
9
10impl ProtectedMemory {
11 pub unsafe fn new(data: *mut u8, size: usize) -> Result<Self> { unsafe {
12 if data.is_null() || size == 0 {
13 return Err(SubstrateError::NullPointer);
14 }
15
16 let page_size = sysconf(_SC_PAGESIZE) as usize;
17 let base = (data as usize / page_size) * page_size;
18 let width = ((data as usize + size - 1) / page_size + 1) * page_size - base;
19 let address = base as *mut u8;
20
21 let result = mprotect(
22 address as *mut c_void,
23 width,
24 PROT_READ | PROT_WRITE | PROT_EXEC,
25 );
26
27 if result == -1 {
28 let err = std::io::Error::last_os_error();
29 return Err(SubstrateError::MemoryProtection(format!("{}", err)));
30 }
31
32 Ok(Self { address, width })
33 }}
34}
35
36impl Drop for ProtectedMemory {
37 fn drop(&mut self) {
38 unsafe {
39 mprotect(
40 self.address as *mut c_void,
41 self.width,
42 PROT_READ | PROT_EXEC,
43 );
44
45 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
46 {
47 unsafe extern "C" {
48 fn __clear_cache(begin: *mut u8, end: *mut u8);
49 }
50 __clear_cache(self.address, self.address.add(self.width));
51 }
52 }
53 }
54}
55
56pub unsafe fn allocate_trampoline(size: usize) -> Result<*mut u8> { unsafe {
57 let ptr = mmap(
58 ptr::null_mut(),
59 size,
60 PROT_READ | PROT_WRITE,
61 MAP_ANON | MAP_PRIVATE,
62 -1,
63 0,
64 );
65
66 if ptr == MAP_FAILED {
67 let err = std::io::Error::last_os_error();
68 return Err(SubstrateError::MemoryMap(format!("{}", err)));
69 }
70
71 Ok(ptr as *mut u8)
72}}
73
74pub unsafe fn make_executable(ptr: *mut u8, size: usize) -> Result<()> { unsafe {
75 let result = mprotect(ptr as *mut c_void, size, PROT_READ | PROT_EXEC);
76
77 if result == -1 {
78 let err = std::io::Error::last_os_error();
79 return Err(SubstrateError::MemoryProtection(format!("{}", err)));
80 }
81
82 Ok(())
83}}
84
85pub unsafe fn free_trampoline(ptr: *mut u8, size: usize) { unsafe {
86 munmap(ptr as *mut c_void, size);
87}}