shadow_rs/host/memory_manager/mod.rs
1//! Access and manage memory of a plugin process.
2//!
3//! The starting point for the public API is [`MemoryManager`].
4//! [`MemoryManager`] can be used to:
5//!
6//! * Directly read or write process memory
7//! * Obtain smart pointers ([`ProcessMemoryRef`] and [`ProcessMemoryRefMut`])
8//! to process memory
9//! * Obtain cursors to process memory implementing `std::io::Seek` and either
10//! `std::io::Read` or `std::io::Write` ([`MemoryReaderCursor`] and
11//! [`MemoryWriterCursor`])
12//!
13//! For the [`MemoryManager`] to maintain a consistent view of the process's address space,
14//! and for it to be able to enforce Rust's safety requirements for references and sharing,
15//! all access to process memory must go through it. This includes servicing syscalls that
16//! modify the process address space (such as `mmap`).
17
18use std::fmt::Debug;
19use std::mem::MaybeUninit;
20use std::ops::{Deref, DerefMut};
21use std::os::raw::c_void;
22
23use linux_api::errno::Errno;
24use linux_api::mman::{MapFlags, ProtFlags};
25use linux_api::posix_types::Pid;
26use log::*;
27use memory_copier::MemoryCopier;
28use memory_mapper::MemoryMapper;
29use shadow_pod::Pod;
30use shadow_shim_helper_rs::syscall_types::ForeignPtr;
31
32use super::context::ThreadContext;
33use crate::host::syscall::types::{ForeignArrayPtr, SyscallError};
34
35mod memory_copier;
36mod memory_mapper;
37
38/// An object implementing std::io::Read and std::io::Seek for
39/// a range of plugin memory.
40pub struct MemoryReaderCursor<'a> {
41 memory_manager: &'a MemoryManager,
42 ptr: ForeignArrayPtr<u8>,
43 offset: usize,
44}
45
46impl std::io::Read for MemoryReaderCursor<'_> {
47 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
48 let ptr = self.ptr.slice(self.offset..);
49 let toread = std::cmp::min(buf.len(), ptr.len());
50 if toread == 0 {
51 return Ok(0);
52 }
53 self.memory_manager
54 .copy_from_ptr(&mut buf[..toread], ptr.slice(..toread))?;
55 self.offset += toread;
56 Ok(toread)
57 }
58}
59
60/// Shared implementation of seek for both MemoryReaderCursor and MemoryWriterCursor.
61fn seek_helper(offset: &mut usize, len: usize, pos: std::io::SeekFrom) -> std::io::Result<u64> {
62 use std::io::SeekFrom;
63 let new_offset = match pos {
64 SeekFrom::Current(x) => *offset as i64 + x,
65 SeekFrom::End(x) => len as i64 + x,
66 SeekFrom::Start(x) => x as i64,
67 };
68 // Seeking before the beginning is an error (but seeking to or past the
69 // end isn't).
70 if new_offset < 0 {
71 return Err(Errno::EFAULT.into());
72 }
73 *offset = new_offset as usize;
74 Ok(new_offset as u64)
75}
76
77impl std::io::Seek for MemoryReaderCursor<'_> {
78 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
79 seek_helper(&mut self.offset, self.ptr.len(), pos)
80 }
81}
82
83/// An object implementing std::io::Write and std::io::Seek for
84/// a range of plugin memory.
85pub struct MemoryWriterCursor<'a> {
86 memory_manager: &'a mut MemoryManager,
87 ptr: ForeignArrayPtr<u8>,
88 offset: usize,
89}
90
91impl std::io::Write for MemoryWriterCursor<'_> {
92 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
93 let ptr = self.ptr.slice(self.offset..);
94 let towrite = std::cmp::min(buf.len(), ptr.len());
95 if towrite == 0 {
96 return Ok(0);
97 }
98 self.memory_manager
99 .copy_to_ptr(ptr.slice(..towrite), &buf[..towrite])?;
100 self.offset += towrite;
101 Ok(towrite)
102 }
103
104 fn flush(&mut self) -> std::io::Result<()> {
105 Ok(())
106 }
107}
108
109impl std::io::Seek for MemoryWriterCursor<'_> {
110 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
111 seek_helper(&mut self.offset, self.ptr.len(), pos)
112 }
113}
114
115enum CopiedOrMapped<'a, T: Debug + Pod> {
116 // Data copied from plugin memory.
117 Copied(Vec<T>),
118 // Data memory-mapped from plugin memory.
119 Mapped(&'a [T]),
120}
121
122/// An immutable reference to a slice of plugin memory. Implements `Deref<[T]>`,
123/// allowing, e.g.:
124///
125/// ```ignore
126/// let tpp = ForeignArrayPtr::<u32>::new(ptr, 10);
127/// let pmr = memory_manager.memory_ref(ptr);
128/// assert_eq!(pmr.len(), 10);
129/// let x = pmr[5];
130/// ```
131pub struct ProcessMemoryRef<'a, T: Debug + Pod>(CopiedOrMapped<'a, T>);
132
133impl<'a, T: Debug + Pod> ProcessMemoryRef<'a, T> {
134 fn new_copied(v: Vec<T>) -> Self {
135 Self(CopiedOrMapped::Copied(v))
136 }
137
138 fn new_mapped(s: &'a [T]) -> Self {
139 Self(CopiedOrMapped::Mapped(s))
140 }
141}
142
143impl ProcessMemoryRef<'_, u8> {
144 /// Get a `cstr` from the reference. Fails with `ENAMETOOLONG` if there is no
145 /// NULL byte.
146 pub fn get_cstr(&self) -> Result<&std::ffi::CStr, Errno> {
147 std::ffi::CStr::from_bytes_until_nul(self).or(Err(Errno::ENAMETOOLONG))
148 }
149}
150
151impl<T> Deref for ProcessMemoryRef<'_, T>
152where
153 T: Debug + Pod,
154{
155 type Target = [T];
156
157 fn deref(&self) -> &Self::Target {
158 match &self.0 {
159 CopiedOrMapped::Copied(v) => v,
160 CopiedOrMapped::Mapped(s) => s,
161 }
162 }
163}
164
165#[derive(Debug)]
166enum CopiedOrMappedMut<'a, T: Debug + Pod> {
167 // Data copied from process memory, to be written back.
168 Copied(MemoryCopier, ForeignArrayPtr<T>, Vec<T>),
169 // Memory-mapped process memory.
170 Mapped(&'a mut [T]),
171}
172
173/// A mutable reference to a slice of plugin memory. Implements `DerefMut<[T]>`,
174/// allowing, e.g.:
175///
176/// ```ignore
177/// let tpp = ForeignArrayPtr::<u32>::new(ptr, 10);
178/// let pmr = memory_manager.memory_ref_mut(ptr);
179/// assert_eq!(pmr.len(), 10);
180/// pmr[5] = 100;
181/// ```
182///
183/// The object must be disposed of by calling `flush` or `noflush`. Dropping
184/// the object without doing so will result in a panic.
185#[derive(Debug)]
186pub struct ProcessMemoryRefMut<'a, T: Debug + Pod> {
187 copied_or_mapped: CopiedOrMappedMut<'a, T>,
188 dirty: bool,
189}
190
191impl<'a, T: Debug + Pod> ProcessMemoryRefMut<'a, T> {
192 fn new_copied(copier: MemoryCopier, ptr: ForeignArrayPtr<T>, v: Vec<T>) -> Self {
193 Self {
194 copied_or_mapped: CopiedOrMappedMut::Copied(copier, ptr, v),
195 dirty: true,
196 }
197 }
198
199 fn new_mapped(s: &'a mut [T]) -> Self {
200 Self {
201 copied_or_mapped: CopiedOrMappedMut::Mapped(s),
202 dirty: true,
203 }
204 }
205
206 /// Call to dispose of the reference while writing back the contents
207 /// to process memory (if it hasn't already effectively been done).
208 ///
209 /// WARNING: if this reference was obtained via
210 /// `Memorymanager::memory_ref_mut_uninit`, and the contents haven't been
211 /// overwritten, call `noflush` instead to avoid flushing back the
212 /// unininitialized contents.
213 pub fn flush(mut self) -> Result<(), Errno> {
214 // Whether the flush succeeds or not, the buffer is no longer considered
215 // dirty; the fact that it failed will be captured in an error result.
216 self.dirty = false;
217
218 match &self.copied_or_mapped {
219 CopiedOrMappedMut::Copied(copier, ptr, v) => {
220 trace!(
221 "Flushing {} bytes to {:x}",
222 ptr.len() * std::mem::size_of::<T>(),
223 usize::from(ptr.ptr())
224 );
225 unsafe { copier.copy_to_ptr(*ptr, v)? };
226 }
227 CopiedOrMappedMut::Mapped(_) => (),
228 };
229 Ok(())
230 }
231
232 /// Disposes of the reference *without* writing back the contents.
233 /// This should be used instead of `flush` if and only if the contents
234 /// of this reference hasn't been overwritten.
235 pub fn noflush(mut self) {
236 self.dirty = false;
237 }
238}
239
240impl<T: Debug + Pod> Drop for ProcessMemoryRefMut<'_, T> {
241 fn drop(&mut self) {
242 // Dropping without flushing is a bug.
243 assert!(!self.dirty);
244 }
245}
246
247impl<T> Deref for ProcessMemoryRefMut<'_, T>
248where
249 T: Debug + Pod,
250{
251 type Target = [T];
252
253 fn deref(&self) -> &Self::Target {
254 match &self.copied_or_mapped {
255 CopiedOrMappedMut::Copied(_, _, v) => v,
256 CopiedOrMappedMut::Mapped(s) => s,
257 }
258 }
259}
260
261impl<T> DerefMut for ProcessMemoryRefMut<'_, T>
262where
263 T: Debug + Pod,
264{
265 fn deref_mut(&mut self) -> &mut Self::Target {
266 match &mut self.copied_or_mapped {
267 CopiedOrMappedMut::Copied(_, _, v) => v,
268 CopiedOrMappedMut::Mapped(s) => s,
269 }
270 }
271}
272
273fn page_size() -> usize {
274 nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)
275 .unwrap()
276 .unwrap()
277 .try_into()
278 .unwrap()
279}
280
281/// Provides accessors for reading and writing another process's memory.
282///
283/// When in use, any operation that touches that process's memory must go
284/// through the MemoryManager to ensure soundness. See MemoryManager::new.
285//
286// The MemoryManager is the Rust representation of a plugin process's address
287// space. For every access it tries to go through the more-efficient
288// MemoryMapper helper first, and falls back to the MemoryCopier if it hasn't
289// been initialized yet, or the access isn't contained entirely within a region
290// that's been remapped.
291#[derive(Debug)]
292pub struct MemoryManager {
293 // Memory accessor that works by copying data to and from process memory.
294 // This is the most robust mechanism, but requires some syscalls, and in
295 // some cases extra copies of the referenced data.
296 memory_copier: MemoryCopier,
297
298 // Memory accessor that works by remapping memory of the target process into
299 // the calling process's address space. Individual accesses are fast, but
300 // this accessor isn't available at program start, and doesn't support all
301 // accesses.
302 memory_mapper: Option<MemoryMapper>,
303
304 // Native pid of the plugin process.
305 pid: Pid,
306}
307
308impl MemoryManager {
309 /// # Safety
310 ///
311 /// `pid`'s memory must not be modified without holding an exclusive
312 /// (mutable) reference to the returned MemoryManager. In Shadow we ensure
313 /// this by:
314 /// * Creating only one MemoryManager for a given process.
315 /// * TODO: Not allowing any thread in the process to execute without
316 /// holding a mutable reference to its MemoryManager.
317 /// * Not directly modifying process memory via other techniques.
318 /// * Assuming (!) nothing else concurrently modifies memory of the given process.
319 /// (e.g. that some other process doesn't start calling `process_vm_writev`
320 /// to write to the process's memory).
321 /// * TODO: Validating that the process doesn't have any shared memory mappings
322 /// other than with Shadow or other simulated processes under Shadow's control.
323 pub unsafe fn new(pid: Pid) -> Self {
324 Self {
325 pid,
326 memory_copier: MemoryCopier::new(pid),
327 memory_mapper: None,
328 }
329 }
330
331 // Internal helper for getting a reference to memory via the
332 // `memory_mapper`. Calling methods should fall back to the `memory_copier`
333 // on failure.
334 fn mapped_ref<T: Pod + Debug>(&self, ptr: ForeignArrayPtr<T>) -> Option<&[T]> {
335 let mm = self.memory_mapper.as_ref()?;
336 // SAFETY: No mutable refs to process memory exist by preconditions of
337 // MemoryManager::new + we have a reference.
338 unsafe { mm.get_ref(ptr) }
339 }
340
341 // Internal helper for getting a reference to memory via the
342 // `memory_mapper`. Calling methods should fall back to the `memory_copier`
343 // on failure.
344 fn mapped_mut<T: Pod + Debug>(&mut self, ptr: ForeignArrayPtr<T>) -> Option<&mut [T]> {
345 let mm = self.memory_mapper.as_ref()?;
346 // SAFETY: No other refs to process memory exist by preconditions of
347 // MemoryManager::new + we have an exclusive reference.
348 unsafe { mm.get_mut(ptr) }
349 }
350
351 /// Returns a reference to the given memory, copying to a local buffer if
352 /// the memory isn't mapped into Shadow.
353 pub fn memory_ref<T: Pod + Debug>(
354 &self,
355 ptr: ForeignArrayPtr<T>,
356 ) -> Result<ProcessMemoryRef<'_, T>, Errno> {
357 if let Some(mref) = self.mapped_ref(ptr) {
358 Ok(ProcessMemoryRef::new_mapped(mref))
359 } else {
360 Ok(ProcessMemoryRef::new_copied(unsafe {
361 self.memory_copier.clone_mem(ptr)?
362 }))
363 }
364 }
365
366 /// Returns a reference to the memory from the beginning of the given
367 /// pointer to the last address in the pointer that's accessible. Useful for
368 /// accessing string data of unknown size. The data is copied to a local
369 /// buffer if the memory isn't mapped into Shadow.
370 pub fn memory_ref_prefix<T: Pod + Debug>(
371 &self,
372 ptr: ForeignArrayPtr<T>,
373 ) -> Result<ProcessMemoryRef<T>, Errno> {
374 // Only use the mapped ref if it's able to get the whole region,
375 // since otherwise the copying version might be able to get more
376 // data.
377 //
378 // TODO: Implement and use MemoryMapper::memory_ref_prefix if and
379 // when we're confident that the MemoryMapper always knows about all
380 // mapped regions and merges adjacent regions.
381 if let Some(mref) = self.mapped_ref(ptr) {
382 Ok(ProcessMemoryRef::new_mapped(mref))
383 } else {
384 Ok(ProcessMemoryRef::new_copied(unsafe {
385 self.memory_copier.clone_mem_prefix(ptr)?
386 }))
387 }
388 }
389
390 /// Creates a std::io::Read accessor for the specified plugin memory. Useful
391 /// for handing off the ability to read process memory to non-Shadow APIs,
392 /// without copying it to local memory first.
393 pub fn reader(&self, ptr: ForeignArrayPtr<u8>) -> MemoryReaderCursor<'_> {
394 MemoryReaderCursor {
395 memory_manager: self,
396 ptr,
397 offset: 0,
398 }
399 }
400
401 /// Reads the memory into a local copy. `memory_ref` is potentially more
402 /// efficient, but this is useful to avoid borrowing from the MemoryManager;
403 /// e.g. when we still want to be able to access the data while also writing
404 /// to process memory.
405 ///
406 /// Examples:
407 ///
408 /// ```no_run
409 /// # use shadow_shim_helper_rs::syscall_types::ForeignPtr;
410 /// # use shadow_rs::host::memory_manager::MemoryManager;
411 /// # use linux_api::errno::Errno;
412 /// # fn foo() -> Result<(), Errno> {
413 /// # let memory_manager: MemoryManager = todo!();
414 /// let ptr: ForeignPtr<u32> = todo!();
415 /// let val: u32 = memory_manager.read(ptr)?;
416 /// # Ok(())
417 /// # }
418 /// ```
419 ///
420 /// ```no_run
421 /// # use shadow_shim_helper_rs::syscall_types::ForeignPtr;
422 /// # use shadow_rs::host::memory_manager::MemoryManager;
423 /// # use linux_api::errno::Errno;
424 /// # fn foo() -> Result<(), Errno> {
425 /// # let memory_manager: MemoryManager = todo!();
426 /// let ptr: ForeignPtr<[u32; 2]> = todo!();
427 /// let val: [u32; 2] = memory_manager.read(ptr)?;
428 /// # Ok(())
429 /// # }
430 /// ```
431 pub fn read<T: Pod + Debug>(&self, ptr: ForeignPtr<T>) -> Result<T, Errno> {
432 let ptr = ptr.cast::<MaybeUninit<T>>();
433 let mut res: MaybeUninit<T> = MaybeUninit::uninit();
434
435 self.copy_from_ptr(std::slice::from_mut(&mut res), ForeignArrayPtr::new(ptr, 1))?;
436 // SAFETY: any values are valid for Pod
437 Ok(unsafe { res.assume_init() })
438 }
439
440 /// Writes a local value `val` into the memory at `ptr`.
441 ///
442 /// ```no_run
443 /// # use shadow_shim_helper_rs::syscall_types::ForeignPtr;
444 /// # use shadow_rs::host::memory_manager::MemoryManager;
445 /// # use linux_api::errno::Errno;
446 /// # fn foo() -> Result<(), Errno> {
447 /// # let mut memory_manager: MemoryManager = todo!();
448 /// let ptr: ForeignPtr<u32> = todo!();
449 /// let val = 5;
450 /// memory_manager.write(ptr, &val)?;
451 /// # Ok(())
452 /// # }
453 /// ```
454 // take a `&T` rather than a `T` since all `Pod` types are `Copy`, and it's probably more
455 // performant to accept a reference than copying the type here if `T` is large
456 pub fn write<T: Pod + Debug>(&mut self, ptr: ForeignPtr<T>, val: &T) -> Result<(), Errno> {
457 self.copy_to_ptr(ForeignArrayPtr::new(ptr, 1), std::slice::from_ref(val))
458 }
459
460 /// Similar to `read`, but saves a copy if you already have a `dst` to copy the data into.
461 pub fn copy_from_ptr<T: Debug + Pod>(
462 &self,
463 dst: &mut [T],
464 src: ForeignArrayPtr<T>,
465 ) -> Result<(), Errno> {
466 if let Some(src) = self.mapped_ref(src) {
467 dst.copy_from_slice(src);
468 return Ok(());
469 }
470 unsafe { self.memory_copier.copy_from_ptr(dst, src) }
471 }
472
473 // Copies memory from the beginning of the given pointer to the last address
474 // in the pointer that's accessible. Not exposed as a public interface
475 // because this is generally only useful for strings, and
476 // `copy_str_from_ptr` provides a more convenient interface.
477 fn copy_prefix_from_ptr<T: Debug + Pod>(
478 &self,
479 buf: &mut [T],
480 ptr: ForeignArrayPtr<T>,
481 ) -> Result<usize, Errno> {
482 if let Some(src) = self.mapped_ref(ptr) {
483 buf.copy_from_slice(src);
484 return Ok(src.len());
485 }
486 unsafe { self.memory_copier.copy_prefix_from_ptr(buf, ptr) }
487 }
488
489 /// Copies a NULL-terminated string starting from the beginning of `src` and
490 /// contained completely within `src`. Still works if some of `src` isn't
491 /// readable, as long as a NULL-terminated-string is contained in the
492 /// readable prefix.
493 ///
494 /// If holding a reference to the MemoryManager for the lifetime of the
495 /// string is acceptable, use `memory_ref_prefix` and
496 /// `ProcessMemoryRef::get_str` to potentially avoid an extra copy.
497 pub fn copy_str_from_ptr<'a>(
498 &self,
499 dst: &'a mut [u8],
500 src: ForeignArrayPtr<u8>,
501 ) -> Result<&'a std::ffi::CStr, Errno> {
502 let nread = self.copy_prefix_from_ptr(dst, src)?;
503 let dst = &dst[..nread];
504 std::ffi::CStr::from_bytes_until_nul(dst).or(Err(Errno::ENAMETOOLONG))
505 }
506
507 /// Returns a mutable reference to the given memory. If the memory isn't
508 /// mapped into Shadow, copies the data to a local buffer, which is written
509 /// back into the process if and when the reference is flushed.
510 pub fn memory_ref_mut<T: Pod + Debug>(
511 &mut self,
512 ptr: ForeignArrayPtr<T>,
513 ) -> Result<ProcessMemoryRefMut<'_, T>, Errno> {
514 // Work around a limitation of the borrow checker by getting this
515 // immutable borrow of self out of the way before we do a mutable
516 // borrow.
517 let pid = self.pid;
518
519 if let Some(mref) = self.mapped_mut(ptr) {
520 Ok(ProcessMemoryRefMut::new_mapped(mref))
521 } else {
522 let copier = MemoryCopier::new(pid);
523 let v = unsafe { copier.clone_mem(ptr)? };
524 Ok(ProcessMemoryRefMut::new_copied(copier, ptr, v))
525 }
526 }
527
528 /// Returns a mutable reference to the given memory. If the memory isn't
529 /// mapped into Shadow, just returns a buffer with unspecified contents,
530 /// which will be written back into the process if and when the reference
531 /// is flushed.
532 //
533 // In some cases we initialize data to avoid actually returning
534 // uninitialized memory. We use inline(always) so that the compiler can
535 // hopefully optimize away this initialization, in cases where the caller
536 // overwrites the data.
537 // TODO: return ProcessMemoryRefMut<MaybeUninit<T>> instead.
538 #[inline(always)]
539 pub fn memory_ref_mut_uninit<T: Pod + Debug>(
540 &mut self,
541 ptr: ForeignArrayPtr<T>,
542 ) -> Result<ProcessMemoryRefMut<'_, T>, Errno> {
543 // Work around a limitation of the borrow checker by getting this
544 // immutable borrow of self out of the way before we do a mutable
545 // borrow.
546 let pid = self.pid;
547
548 let mut mref = if let Some(mref) = self.mapped_mut(ptr) {
549 // Even if we haven't initialized the data from this process, the
550 // data is initialized from the Rust compiler's perspective; it has
551 // *some* set contents via mmap, even if the other process hasn't
552 // initialized it either.
553 ProcessMemoryRefMut::new_mapped(mref)
554 } else {
555 let mut v = Vec::with_capacity(ptr.len());
556 v.resize(ptr.len(), shadow_pod::zeroed());
557 ProcessMemoryRefMut::new_copied(MemoryCopier::new(pid), ptr, v)
558 };
559
560 // In debug builds, overwrite with garbage to shake out bugs where
561 // caller treats as initd; e.g. by reading the data or flushing it
562 // back to the process without initializing it.
563 if cfg!(debug_assertions) {
564 // SAFETY: We do not write uninitialized data into `bytes`.
565 let bytes = unsafe { shadow_pod::to_u8_slice_mut(&mut mref[..]) };
566 for byte in bytes {
567 unsafe { byte.as_mut_ptr().write(0x42) }
568 }
569 }
570
571 Ok(mref)
572 }
573
574 /// Writes the memory from a local copy. If `src` doesn't already exist,
575 /// using `memory_ref_mut_uninit` and initializing the data in that
576 /// reference saves a copy.
577 pub fn copy_to_ptr<T: Pod + Debug>(
578 &mut self,
579 dst: ForeignArrayPtr<T>,
580 src: &[T],
581 ) -> Result<(), Errno> {
582 if let Some(dst) = self.mapped_mut(dst) {
583 dst.copy_from_slice(src);
584 return Ok(());
585 }
586 // SAFETY: No other refs to process memory exist by preconditions of
587 // MemoryManager::new + we have an exclusive reference.
588 unsafe { self.memory_copier.copy_to_ptr(dst, src) }
589 }
590
591 /// Which process's address space this MemoryManager manages.
592 pub fn pid(&self) -> Pid {
593 self.pid
594 }
595
596 /// Initialize the MemoryMapper, allowing for more efficient access. Needs a
597 /// running thread.
598 pub fn init_mapper(&mut self, ctx: &ThreadContext) {
599 assert!(self.memory_mapper.is_none());
600 self.memory_mapper = Some(MemoryMapper::new(self, ctx));
601 }
602
603 /// Whether the internal MemoryMapper has been initialized.
604 pub fn has_mapper(&self) -> bool {
605 self.memory_mapper.is_some()
606 }
607
608 /// Create a write accessor for the specified plugin memory.
609 pub fn writer(&mut self, ptr: ForeignArrayPtr<u8>) -> MemoryWriterCursor<'_> {
610 MemoryWriterCursor {
611 memory_manager: self,
612 ptr,
613 offset: 0,
614 }
615 }
616
617 pub fn handle_brk(
618 &mut self,
619 ctx: &ThreadContext,
620 ptr: ForeignPtr<u8>,
621 ) -> Result<ForeignPtr<u8>, SyscallError> {
622 match &mut self.memory_mapper {
623 Some(mm) => Ok(mm.handle_brk(ctx, ptr)?),
624 None => Err(SyscallError::Native),
625 }
626 }
627
628 pub fn do_mmap(
629 &mut self,
630 ctx: &ThreadContext,
631 addr: ForeignPtr<u8>,
632 length: usize,
633 prot: ProtFlags,
634 flags: MapFlags,
635 fd: i32,
636 offset: i64,
637 ) -> Result<ForeignPtr<u8>, Errno> {
638 let addr = {
639 let (ctx, thread) = ctx.split_thread();
640 thread.native_mmap(&ctx, addr, length, prot, flags, fd, offset)?
641 };
642 if let Some(mm) = &mut self.memory_mapper {
643 mm.handle_mmap_result(ctx, ForeignArrayPtr::new(addr, length), prot, flags, fd);
644 }
645 Ok(addr)
646 }
647
648 pub fn handle_munmap(
649 &mut self,
650 ctx: &ThreadContext,
651 addr: ForeignPtr<u8>,
652 length: usize,
653 ) -> Result<(), SyscallError> {
654 if self.memory_mapper.is_some() {
655 // Do it ourselves so that we can update our mappings based on
656 // whether it succeeded.
657 self.do_munmap(ctx, addr, length)?;
658 Ok(())
659 } else {
660 // We don't need to know the result, and it's more efficient to let
661 // the original syscall complete than to do it ourselves.
662 Err(SyscallError::Native)
663 }
664 }
665
666 fn do_munmap(
667 &mut self,
668 ctx: &ThreadContext,
669 addr: ForeignPtr<u8>,
670 length: usize,
671 ) -> Result<(), Errno> {
672 let (ctx, thread) = ctx.split_thread();
673 thread.native_munmap(&ctx, addr, length)?;
674 if let Some(mm) = &mut self.memory_mapper {
675 mm.handle_munmap_result(addr, length);
676 }
677 Ok(())
678 }
679
680 pub fn handle_mremap(
681 &mut self,
682 ctx: &ThreadContext,
683 old_address: ForeignPtr<u8>,
684 old_size: usize,
685 new_size: usize,
686 flags: i32,
687 new_address: ForeignPtr<u8>,
688 ) -> Result<ForeignPtr<u8>, SyscallError> {
689 match &mut self.memory_mapper {
690 Some(mm) => {
691 Ok(mm.handle_mremap(ctx, old_address, old_size, new_size, flags, new_address)?)
692 }
693 None => Err(SyscallError::Native),
694 }
695 }
696
697 pub fn handle_mprotect(
698 &mut self,
699 ctx: &ThreadContext,
700 addr: ForeignPtr<u8>,
701 size: usize,
702 prot: ProtFlags,
703 ) -> Result<(), SyscallError> {
704 match &mut self.memory_mapper {
705 Some(mm) => Ok(mm.handle_mprotect(ctx, addr, size, prot)?),
706 None => Err(SyscallError::Native),
707 }
708 }
709}
710
711/// Memory allocated by Shadow, in a remote address space.
712pub struct AllocdMem<T>
713where
714 T: Pod,
715{
716 ptr: ForeignArrayPtr<T>,
717 // Whether the pointer has been freed.
718 freed: bool,
719}
720
721impl<T> AllocdMem<T>
722where
723 T: Pod,
724{
725 /// Allocate memory in the current active process.
726 /// Must be freed explicitly via `free`.
727 pub fn new(ctx: &ThreadContext, len: usize) -> Self {
728 let prot = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE;
729
730 // Allocate through the MemoryManager, so that it knows about this region.
731 let ptr = ctx
732 .process
733 .memory_borrow_mut()
734 .do_mmap(
735 ctx,
736 ForeignPtr::null(),
737 len * std::mem::size_of::<T>(),
738 prot,
739 MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE,
740 -1,
741 0,
742 )
743 .unwrap();
744
745 Self {
746 ptr: ForeignArrayPtr::new(ptr.cast::<T>(), len),
747 freed: false,
748 }
749 }
750
751 /// Pointer to the allocated memory.
752 pub fn ptr(&self) -> ForeignArrayPtr<T> {
753 self.ptr
754 }
755
756 pub fn free(mut self, ctx: &ThreadContext) {
757 ctx.process
758 .memory_borrow_mut()
759 .do_munmap(
760 ctx,
761 self.ptr.ptr().cast::<u8>(),
762 self.ptr.len() * std::mem::size_of::<T>(),
763 )
764 .unwrap();
765 self.freed = true;
766 }
767}
768
769impl<T> Drop for AllocdMem<T>
770where
771 T: Pod,
772{
773 fn drop(&mut self) {
774 // We need the thread context to free the memory. Nothing to do now but
775 // complain.
776 if !self.freed {
777 warn!("Memory leak: failed to free {:?}", self.ptr)
778 }
779 debug_assert!(self.freed);
780 }
781}
782
783mod export {
784 use shadow_shim_helper_rs::notnull::*;
785 use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
786
787 use super::*;
788
789 /// Copy `n` bytes from `src` to `dst`. Returns 0 on success or -EFAULT if any of the specified
790 /// range couldn't be accessed. Always succeeds with n==0.
791 #[unsafe(no_mangle)]
792 pub extern "C-unwind" fn memorymanager_readPtr(
793 mem: *const MemoryManager,
794 dst: *mut c_void,
795 src: UntypedForeignPtr,
796 n: usize,
797 ) -> i32 {
798 let mem = unsafe { mem.as_ref() }.unwrap();
799 let src = ForeignArrayPtr::new(src.cast::<u8>(), n);
800 let dst = unsafe { std::slice::from_raw_parts_mut(notnull_mut_debug(dst) as *mut u8, n) };
801
802 match mem.copy_from_ptr(dst, src) {
803 Ok(_) => 0,
804 Err(e) => {
805 trace!("Couldn't read {:?} into {:?}: {:?}", src, dst, e);
806 e.to_negated_i32()
807 }
808 }
809 }
810
811 /// Copy `n` bytes from `src` to `dst`. Returns 0 on success or -EFAULT if any of the specified
812 /// range couldn't be accessed. The write is flushed immediately.
813 #[unsafe(no_mangle)]
814 pub unsafe extern "C-unwind" fn memorymanager_writePtr(
815 mem: *mut MemoryManager,
816 dst: UntypedForeignPtr,
817 src: *const c_void,
818 n: usize,
819 ) -> i32 {
820 let mem = unsafe { mem.as_mut() }.unwrap();
821 let dst = ForeignArrayPtr::new(dst.cast::<u8>(), n);
822 let src = unsafe { std::slice::from_raw_parts(notnull_debug(src) as *const u8, n) };
823 match mem.copy_to_ptr(dst, src) {
824 Ok(_) => 0,
825 Err(e) => {
826 trace!("Couldn't write {:?} into {:?}: {:?}", src, dst, e);
827 e.to_negated_i32()
828 }
829 }
830 }
831}