substrate/hook/
memory.rs

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}}