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}