process_backend/local/
module_reader.rs1use {
2 super::{Error, OwnedFd, SyscallInvoker, errno},
3 core::{
4 ffi::{CStr, c_void},
5 mem, ptr,
6 },
7};
8
9#[derive(Debug)]
10pub struct MappedModuleMemoryReader {
11 mapped: Mapped,
12 ptr: *mut u8,
13 len: usize,
14}
15
16impl MappedModuleMemoryReader {
17 pub fn new(
18 syscall_invoker: &mut SyscallInvoker,
19 path: &CStr,
20 start_position: u64,
21 ) -> Result<Self, Error> {
22 let fd = Self::open_file(syscall_invoker, path)?;
23
24 let end_position = Self::get_file_size(syscall_invoker, &fd)?;
27
28 if start_position > end_position {
29 Err(Error::StartPositionPastEnd)?;
30 }
31
32 let page_size = Self::get_page_size();
34 let offset_into_page = start_position % page_size;
35 let aligned_start_position = start_position - offset_into_page;
36 let mmap_length = usize::try_from(end_position - aligned_start_position)
37 .map_err(|_| Error::MappingTooLarge)?;
38
39 let mapped = Self::map_memory(syscall_invoker, &fd, aligned_start_position, mmap_length)?;
40
41 drop(fd);
44
45 let slice_offset_into_mapping = usize::try_from(offset_into_page).unwrap();
49 let ptr = unsafe { mapped.ptr.cast::<u8>().add(slice_offset_into_mapping) };
50 let len = mmap_length - slice_offset_into_mapping;
51
52 Ok(MappedModuleMemoryReader { mapped, ptr, len })
53 }
54 pub fn read(&self, offset: u64, length: u64) -> Result<&[u8], Error> {
55 (|| {
56 let offset = usize::try_from(offset).ok()?;
57 let length = usize::try_from(length).ok()?;
58 let end = offset.checked_add(length)?;
59 self.as_slice().get(offset..end)
60 })()
61 .ok_or(Error::IndexOutOfBounds)
62 }
63 pub fn len(&self) -> Result<usize, Error> {
64 Ok(self.as_slice().len())
65 }
66 pub fn is_empty(&self) -> Result<bool, Error> {
67 self.len().map(|l| l == 0)
68 }
69 fn open_file(syscall_invoker: &mut SyscallInvoker, path: &CStr) -> Result<OwnedFd, Error> {
70 syscall_invoker
71 .invoke_standard(|| unsafe {
72 libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_CLOEXEC, 0)
73 })
74 .map(|fd| unsafe { OwnedFd::new(fd) })
75 .map_err(Error::OpenFileFailed)
76 }
77 fn get_file_size(syscall_invoker: &mut SyscallInvoker, fd: &OwnedFd) -> Result<u64, Error> {
78 let mut stat: libc::stat = unsafe { mem::zeroed() };
79
80 syscall_invoker
81 .invoke_standard(|| unsafe { libc::fstat(fd.as_raw_fd(), &mut stat) })
82 .map_err(Error::StatFailed)?;
83
84 Ok(u64::try_from(stat.st_size).unwrap())
85 }
86 fn get_page_size() -> u64 {
87 let page_size = u64::try_from(unsafe { libc::sysconf(libc::_SC_PAGESIZE) }).unwrap();
88 assert!(page_size > 0);
89 page_size
90 }
91 fn map_memory(
92 syscall_invoker: &mut SyscallInvoker,
93 fd: &OwnedFd,
94 page_aligned_start_position: u64,
95 len: usize,
96 ) -> Result<Mapped, Error> {
97 let len = usize::max(len, 1);
100
101 if len > isize::MAX as usize {
113 Err(Error::MappingTooLarge)?;
114 }
115
116 syscall_invoker
117 .invoke(|| unsafe {
118 let ptr = libc::mmap(
119 ptr::null_mut(),
120 len,
121 libc::PROT_READ,
122 libc::MAP_SHARED,
123 fd.as_raw_fd(),
124 page_aligned_start_position.try_into().unwrap(),
125 );
126 if ptr == libc::MAP_FAILED {
127 return Err(());
128 }
129 Ok(Mapped { ptr, len })
130 })
131 .map_err(Error::MMapfailed)
132 }
133 fn as_slice(&self) -> &[u8] {
134 let _mapped_used = &self.mapped;
138 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
139 }
140}
141
142#[derive(Debug)]
143struct Mapped {
144 ptr: *mut c_void,
145 len: usize,
146}
147
148impl Drop for Mapped {
149 fn drop(&mut self) {
150 let rv = unsafe { libc::munmap(self.ptr, self.len) };
151 if rv == -1 {
152 log::error!("failed to unmap memory: {}", errno());
153 }
154 }
155}