shadow_rs/host/memory_manager/
mod.rs1use std::fmt::Debug;
12use std::mem::MaybeUninit;
13use std::os::raw::c_void;
14
15use linux_api::errno::Errno;
16use linux_api::mman::{MapFlags, ProtFlags};
17use linux_api::posix_types::Pid;
18use log::*;
19use memory_copier::MemoryCopier;
20use shadow_pod::Pod;
21use shadow_shim_helper_rs::syscall_types::ForeignPtr;
22
23use super::context::ThreadContext;
24use crate::host::syscall::types::{ForeignArrayPtr, SyscallError};
25
26mod memory_copier;
27
28pub struct MemoryReaderCursor<'a> {
31 memory_manager: &'a MemoryManager,
32 ptr: ForeignArrayPtr<u8>,
33 offset: usize,
34}
35
36impl std::io::Read for MemoryReaderCursor<'_> {
37 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
38 let ptr = self.ptr.slice(self.offset..);
39 let toread = std::cmp::min(buf.len(), ptr.len());
40 if toread == 0 {
41 return Ok(0);
42 }
43 self.memory_manager
44 .copy_from_ptr(&mut buf[..toread], ptr.slice(..toread))?;
45 self.offset += toread;
46 Ok(toread)
47 }
48}
49
50fn seek_helper(offset: &mut usize, len: usize, pos: std::io::SeekFrom) -> std::io::Result<u64> {
52 use std::io::SeekFrom;
53 let new_offset = match pos {
54 SeekFrom::Current(x) => *offset as i64 + x,
55 SeekFrom::End(x) => len as i64 + x,
56 SeekFrom::Start(x) => x as i64,
57 };
58 if new_offset < 0 {
61 return Err(Errno::EFAULT.into());
62 }
63 *offset = new_offset as usize;
64 Ok(new_offset as u64)
65}
66
67impl std::io::Seek for MemoryReaderCursor<'_> {
68 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
69 seek_helper(&mut self.offset, self.ptr.len(), pos)
70 }
71}
72
73pub struct MemoryWriterCursor<'a> {
76 memory_manager: &'a mut MemoryManager,
77 ptr: ForeignArrayPtr<u8>,
78 offset: usize,
79}
80
81impl std::io::Write for MemoryWriterCursor<'_> {
82 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
83 let ptr = self.ptr.slice(self.offset..);
84 let towrite = std::cmp::min(buf.len(), ptr.len());
85 if towrite == 0 {
86 return Ok(0);
87 }
88 self.memory_manager
89 .copy_to_ptr(ptr.slice(..towrite), &buf[..towrite])?;
90 self.offset += towrite;
91 Ok(towrite)
92 }
93
94 fn flush(&mut self) -> std::io::Result<()> {
95 Ok(())
96 }
97}
98
99impl std::io::Seek for MemoryWriterCursor<'_> {
100 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
101 seek_helper(&mut self.offset, self.ptr.len(), pos)
102 }
103}
104
105fn page_size() -> usize {
106 nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)
107 .unwrap()
108 .unwrap()
109 .try_into()
110 .unwrap()
111}
112
113#[derive(Debug)]
124pub struct MemoryManager {
125 memory_copier: MemoryCopier,
129
130 pid: Pid,
132}
133
134impl MemoryManager {
135 pub fn new(pid: Pid) -> Self {
136 Self {
137 pid,
138 memory_copier: MemoryCopier::new(pid),
139 }
140 }
141
142 pub fn read_prefix<T: Pod>(&self, ptr: ForeignArrayPtr<T>) -> Result<Vec<T>, Errno> {
149 let ptr = ptr.cast::<MaybeUninit<T>>().unwrap();
150 let mut values = Vec::with_capacity(ptr.len());
151 let copied = self
152 .memory_copier
153 .copy_prefix_from_ptr(values.spare_capacity_mut(), ptr)?;
154 unsafe { values.set_len(copied) };
156 Ok(values)
157 }
158
159 pub fn reader(&self, ptr: ForeignArrayPtr<u8>) -> MemoryReaderCursor<'_> {
163 MemoryReaderCursor {
164 memory_manager: self,
165 ptr,
166 offset: 0,
167 }
168 }
169
170 pub fn read<T: Pod>(&self, ptr: ForeignPtr<T>) -> Result<T, Errno> {
198 let ptr = ptr.cast::<MaybeUninit<T>>();
199 let mut res: MaybeUninit<T> = MaybeUninit::uninit();
200
201 self.copy_from_ptr(std::slice::from_mut(&mut res), ForeignArrayPtr::new(ptr, 1))?;
202 Ok(unsafe { res.assume_init() })
204 }
205
206 pub fn read_vec<T: Pod>(&self, ptr: ForeignArrayPtr<T>) -> Result<Vec<T>, Errno> {
209 let mut values = Box::<[T]>::new_uninit_slice(ptr.len());
210 let ptr = ptr.cast::<MaybeUninit<T>>().unwrap();
211 self.copy_from_ptr(&mut values, ptr)?;
212 let value = unsafe { values.assume_init() };
214 Ok(Vec::from(value))
215 }
216
217 pub fn write<T: Pod>(&mut self, ptr: ForeignPtr<T>, val: &T) -> Result<(), Errno> {
234 self.copy_to_ptr(ForeignArrayPtr::new(ptr, 1), std::slice::from_ref(val))
235 }
236
237 pub fn copy_from_ptr<T: Pod>(
239 &self,
240 dst: &mut [T],
241 src: ForeignArrayPtr<T>,
242 ) -> Result<(), Errno> {
243 self.memory_copier.copy_from_ptr(dst, src)
244 }
245
246 fn copy_prefix_from_ptr<T: Pod>(
251 &self,
252 buf: &mut [T],
253 ptr: ForeignArrayPtr<T>,
254 ) -> Result<usize, Errno> {
255 self.memory_copier.copy_prefix_from_ptr(buf, ptr)
256 }
257
258 pub fn copy_str_from_ptr<'a>(
267 &self,
268 dst: &'a mut [u8],
269 src: ForeignArrayPtr<u8>,
270 ) -> Result<&'a std::ffi::CStr, Errno> {
271 let nread = self.copy_prefix_from_ptr(dst, src)?;
272 let dst = &dst[..nread];
273 std::ffi::CStr::from_bytes_until_nul(dst).or(Err(Errno::ENAMETOOLONG))
274 }
275
276 pub fn copy_to_ptr<T: Pod>(&mut self, dst: ForeignArrayPtr<T>, src: &[T]) -> Result<(), Errno> {
280 self.memory_copier.copy_to_ptr(dst, src)
281 }
282
283 pub fn pid(&self) -> Pid {
285 self.pid
286 }
287
288 pub fn writer(&mut self, ptr: ForeignArrayPtr<u8>) -> MemoryWriterCursor<'_> {
290 MemoryWriterCursor {
291 memory_manager: self,
292 ptr,
293 offset: 0,
294 }
295 }
296
297 pub fn handle_brk(
298 &mut self,
299 _ctx: &ThreadContext,
300 _ptr: ForeignPtr<u8>,
301 ) -> Result<ForeignPtr<u8>, SyscallError> {
302 Err(SyscallError::Native)
303 }
304
305 pub fn do_mmap(
306 &mut self,
307 ctx: &ThreadContext,
308 addr: ForeignPtr<u8>,
309 length: usize,
310 prot: ProtFlags,
311 flags: MapFlags,
312 fd: i32,
313 offset: i64,
314 ) -> Result<ForeignPtr<u8>, Errno> {
315 let addr = {
316 let (ctx, thread) = ctx.split_thread();
317 thread.native_mmap(&ctx, addr, length, prot, flags, fd, offset)?
318 };
319 Ok(addr)
320 }
321
322 pub fn handle_munmap(
323 &mut self,
324 _ctx: &ThreadContext,
325 _addr: ForeignPtr<u8>,
326 _length: usize,
327 ) -> Result<(), SyscallError> {
328 Err(SyscallError::Native)
331 }
332
333 fn do_munmap(
334 &mut self,
335 ctx: &ThreadContext,
336 addr: ForeignPtr<u8>,
337 length: usize,
338 ) -> Result<(), Errno> {
339 let (ctx, thread) = ctx.split_thread();
340 thread.native_munmap(&ctx, addr, length)?;
341 Ok(())
342 }
343
344 pub fn handle_mremap(
345 &mut self,
346 _ctx: &ThreadContext,
347 _old_address: ForeignPtr<u8>,
348 _old_size: usize,
349 _new_size: usize,
350 _flags: i32,
351 _new_address: ForeignPtr<u8>,
352 ) -> Result<ForeignPtr<u8>, SyscallError> {
353 Err(SyscallError::Native)
354 }
355
356 pub fn handle_mprotect(
357 &mut self,
358 _ctx: &ThreadContext,
359 _addr: ForeignPtr<u8>,
360 _size: usize,
361 _prot: ProtFlags,
362 ) -> Result<(), SyscallError> {
363 Err(SyscallError::Native)
364 }
365}
366
367pub struct AllocdMem<T>
369where
370 T: Pod,
371{
372 ptr: ForeignArrayPtr<T>,
373 freed: bool,
375}
376
377impl<T> AllocdMem<T>
378where
379 T: Pod,
380{
381 pub fn new(ctx: &ThreadContext, len: usize) -> Self {
384 let prot = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE;
385
386 let ptr = ctx
388 .process
389 .memory_borrow_mut()
390 .do_mmap(
391 ctx,
392 ForeignPtr::null(),
393 len * std::mem::size_of::<T>(),
394 prot,
395 MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
396 -1,
397 0,
398 )
399 .unwrap();
400
401 Self {
402 ptr: ForeignArrayPtr::new(ptr.cast::<T>(), len),
403 freed: false,
404 }
405 }
406
407 pub fn ptr(&self) -> ForeignArrayPtr<T> {
409 self.ptr
410 }
411
412 pub fn free(mut self, ctx: &ThreadContext) {
413 ctx.process
414 .memory_borrow_mut()
415 .do_munmap(
416 ctx,
417 self.ptr.ptr().cast::<u8>(),
418 self.ptr.len() * std::mem::size_of::<T>(),
419 )
420 .unwrap();
421 self.freed = true;
422 }
423}
424
425impl<T> Drop for AllocdMem<T>
426where
427 T: Pod,
428{
429 fn drop(&mut self) {
430 if !self.freed {
433 warn!("Memory leak: failed to free {:?}", self.ptr)
434 }
435 debug_assert!(self.freed);
436 }
437}
438
439mod export {
440 use shadow_shim_helper_rs::notnull::*;
441 use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
442
443 use super::*;
444
445 #[unsafe(no_mangle)]
448 pub extern "C-unwind" fn memorymanager_readPtr(
449 mem: *const MemoryManager,
450 dst: *mut c_void,
451 src: UntypedForeignPtr,
452 n: usize,
453 ) -> i32 {
454 let mem = unsafe { mem.as_ref() }.unwrap();
455 let src = ForeignArrayPtr::new(src.cast::<u8>(), n);
456 let dst = unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(dst) as *mut u8, n) };
457
458 match mem.copy_from_ptr(dst, src) {
459 Ok(_) => 0,
460 Err(e) => {
461 trace!("Couldn't read {src:?} into {dst:?}: {e:?}");
462 e.to_negated_i32()
463 }
464 }
465 }
466
467 #[unsafe(no_mangle)]
470 pub unsafe extern "C-unwind" fn memorymanager_writePtr(
471 mem: *mut MemoryManager,
472 dst: UntypedForeignPtr,
473 src: *const c_void,
474 n: usize,
475 ) -> i32 {
476 let mem = unsafe { mem.as_mut() }.unwrap();
477 let dst = ForeignArrayPtr::new(dst.cast::<u8>(), n);
478 let src = unsafe { std::slice::from_raw_parts(notnull_debug(src) as *const u8, n) };
479 match mem.copy_to_ptr(dst, src) {
480 Ok(_) => 0,
481 Err(e) => {
482 trace!("Couldn't write {src:?} into {dst:?}: {e:?}");
483 e.to_negated_i32()
484 }
485 }
486 }
487}