• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! The mmap module provides a safe interface to mmap memory and ensures unmap is called when the
6 //! mmap object leaves scope.
7 
8 use std::cmp::min;
9 use std::collections::BTreeMap;
10 use std::fmt::{self, Display};
11 use std::io;
12 use std::mem::{size_of, ManuallyDrop};
13 use std::os::unix::io::AsRawFd;
14 use std::ptr::{copy_nonoverlapping, null_mut, read_unaligned, write_unaligned};
15 
16 use libc::{self, c_int, c_void, read, write};
17 
18 use data_model::volatile_memory::*;
19 use data_model::DataInit;
20 
21 use crate::{errno, pagesize};
22 
23 #[derive(Debug)]
24 pub enum Error {
25     /// Requested memory out of range.
26     InvalidAddress,
27     /// Requested offset is out of range of `libc::off_t`.
28     InvalidOffset,
29     /// Requested mapping is not page aligned
30     NotPageAligned,
31     /// Overlapping regions
32     Overlapping(usize, usize),
33     /// Requested memory range spans past the end of the region.
34     InvalidRange(usize, usize, usize),
35     /// `mmap` returned the given error.
36     SystemCallFailed(errno::Error),
37     /// Writing to memory failed
38     ReadToMemory(io::Error),
39     /// Reading from memory failed
40     WriteFromMemory(io::Error),
41 }
42 pub type Result<T> = std::result::Result<T, Error>;
43 
44 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result45     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46         use self::Error::*;
47 
48         match self {
49             InvalidAddress => write!(f, "requested memory out of range"),
50             InvalidOffset => write!(f, "requested offset is out of range of off_t"),
51             NotPageAligned => write!(f, "requested memory is not page aligned"),
52             Overlapping(offset, count) => write!(
53                 f,
54                 "requested memory range overlaps with existing region: offset={} size={}",
55                 offset, count
56             ),
57             InvalidRange(offset, count, region_size) => write!(
58                 f,
59                 "requested memory range spans past the end of the region: offset={} count={} region_size={}",
60                 offset, count, region_size,
61             ),
62             SystemCallFailed(e) => write!(f, "mmap system call failed: {}", e),
63             ReadToMemory(e) => write!(f, "failed to read from file to memory: {}", e),
64             WriteFromMemory(e) => write!(f, "failed to write from memory to file: {}", e),
65         }
66     }
67 }
68 
69 /// Memory access type for anonymous shared memory mapping.
70 #[derive(Copy, Clone, Eq, PartialEq)]
71 pub struct Protection(c_int);
72 impl Protection {
73     /// Returns Protection allowing no access.
74     #[inline(always)]
none() -> Protection75     pub fn none() -> Protection {
76         Protection(libc::PROT_NONE)
77     }
78 
79     /// Returns Protection allowing read/write access.
80     #[inline(always)]
read_write() -> Protection81     pub fn read_write() -> Protection {
82         Protection(libc::PROT_READ | libc::PROT_WRITE)
83     }
84 
85     /// Returns Protection allowing read access.
86     #[inline(always)]
read() -> Protection87     pub fn read() -> Protection {
88         Protection(libc::PROT_READ)
89     }
90 
91     /// Set read events.
92     #[inline(always)]
set_read(self) -> Protection93     pub fn set_read(self) -> Protection {
94         Protection(self.0 | libc::PROT_READ)
95     }
96 
97     /// Set write events.
98     #[inline(always)]
set_write(self) -> Protection99     pub fn set_write(self) -> Protection {
100         Protection(self.0 | libc::PROT_WRITE)
101     }
102 }
103 
104 impl From<c_int> for Protection {
from(f: c_int) -> Self105     fn from(f: c_int) -> Self {
106         Protection(f)
107     }
108 }
109 
110 impl Into<c_int> for Protection {
into(self) -> c_int111     fn into(self) -> c_int {
112         self.0
113     }
114 }
115 
116 /// Wraps an anonymous shared memory mapping in the current process.
117 #[derive(Debug)]
118 pub struct MemoryMapping {
119     addr: *mut u8,
120     size: usize,
121 }
122 
123 // Send and Sync aren't automatically inherited for the raw address pointer.
124 // Accessing that pointer is only done through the stateless interface which
125 // allows the object to be shared by multiple threads without a decrease in
126 // safety.
127 unsafe impl Send for MemoryMapping {}
128 unsafe impl Sync for MemoryMapping {}
129 
130 impl MemoryMapping {
131     /// Creates an anonymous shared, read/write mapping of `size` bytes.
132     ///
133     /// # Arguments
134     /// * `size` - Size of memory region in bytes.
new(size: usize) -> Result<MemoryMapping>135     pub fn new(size: usize) -> Result<MemoryMapping> {
136         MemoryMapping::new_protection(size, Protection::read_write())
137     }
138 
139     /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
140     ///
141     /// # Arguments
142     /// * `size` - Size of memory region in bytes.
143     /// * `prot` - Protection (e.g. readable/writable) of the memory region.
new_protection(size: usize, prot: Protection) -> Result<MemoryMapping>144     pub fn new_protection(size: usize, prot: Protection) -> Result<MemoryMapping> {
145         // This is safe because we are creating an anonymous mapping in a place not already used by
146         // any other area in this process.
147         unsafe {
148             MemoryMapping::try_mmap(
149                 None,
150                 size,
151                 prot.into(),
152                 libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
153                 None,
154             )
155         }
156     }
157 
158     /// Maps the first `size` bytes of the given `fd` as read/write.
159     ///
160     /// # Arguments
161     /// * `fd` - File descriptor to mmap from.
162     /// * `size` - Size of memory region in bytes.
from_fd(fd: &dyn AsRawFd, size: usize) -> Result<MemoryMapping>163     pub fn from_fd(fd: &dyn AsRawFd, size: usize) -> Result<MemoryMapping> {
164         MemoryMapping::from_fd_offset(fd, size, 0)
165     }
166 
from_fd_offset(fd: &dyn AsRawFd, size: usize, offset: usize) -> Result<MemoryMapping>167     pub fn from_fd_offset(fd: &dyn AsRawFd, size: usize, offset: usize) -> Result<MemoryMapping> {
168         MemoryMapping::from_fd_offset_protection(fd, size, offset, Protection::read_write())
169     }
170 
171     /// Maps the `size` bytes starting at `offset` bytes of the given `fd` as read/write.
172     ///
173     /// # Arguments
174     /// * `fd` - File descriptor to mmap from.
175     /// * `size` - Size of memory region in bytes.
176     /// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
177     /// * `prot` - Protection (e.g. readable/writable) of the memory region.
from_fd_offset_protection( fd: &dyn AsRawFd, size: usize, offset: usize, prot: Protection, ) -> Result<MemoryMapping>178     pub fn from_fd_offset_protection(
179         fd: &dyn AsRawFd,
180         size: usize,
181         offset: usize,
182         prot: Protection,
183     ) -> Result<MemoryMapping> {
184         // This is safe because we are creating an anonymous mapping in a place not already used by
185         // any other area in this process.
186         unsafe {
187             MemoryMapping::try_mmap(
188                 None,
189                 size,
190                 prot.into(),
191                 libc::MAP_SHARED,
192                 Some((fd, offset)),
193             )
194         }
195     }
196 
197     /// Creates an anonymous shared mapping of `size` bytes with `prot` protection.
198     /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
199     ///
200     /// # Arguments
201     /// * `addr` - Memory address to mmap at.
202     /// * `size` - Size of memory region in bytes.
203     /// * `prot` - Protection (e.g. readable/writable) of the memory region.
new_protection_fixed( addr: *mut u8, size: usize, prot: Protection, ) -> Result<MemoryMapping>204     pub unsafe fn new_protection_fixed(
205         addr: *mut u8,
206         size: usize,
207         prot: Protection,
208     ) -> Result<MemoryMapping> {
209         MemoryMapping::try_mmap(
210             Some(addr),
211             size,
212             prot.into(),
213             libc::MAP_ANONYMOUS | libc::MAP_SHARED | libc::MAP_NORESERVE,
214             None,
215         )
216     }
217 
218     /// Maps the `size` bytes starting at `offset` bytes of the given `fd` with
219     /// `prot` protections.
220     /// Unsafe: unmaps any mmap'd regions already present at (addr..addr+size).
221     ///
222     /// # Arguments
223     /// * `addr` - Memory address to mmap at.
224     /// * `fd` - File descriptor to mmap from.
225     /// * `size` - Size of memory region in bytes.
226     /// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
227     /// * `prot` - Protection (e.g. readable/writable) of the memory region.
from_fd_offset_protection_fixed( addr: *mut u8, fd: &dyn AsRawFd, size: usize, offset: usize, prot: Protection, ) -> Result<MemoryMapping>228     pub unsafe fn from_fd_offset_protection_fixed(
229         addr: *mut u8,
230         fd: &dyn AsRawFd,
231         size: usize,
232         offset: usize,
233         prot: Protection,
234     ) -> Result<MemoryMapping> {
235         MemoryMapping::try_mmap(
236             Some(addr),
237             size,
238             prot.into(),
239             libc::MAP_SHARED | libc::MAP_NORESERVE,
240             Some((fd, offset)),
241         )
242     }
243 
244     /// Helper wrapper around libc::mmap that does some basic validation, and calls
245     /// madvise with MADV_DONTDUMP on the created mmap
try_mmap( addr: Option<*mut u8>, size: usize, prot: c_int, flags: c_int, fd: Option<(&AsRawFd, usize)>, ) -> Result<MemoryMapping>246     unsafe fn try_mmap(
247         addr: Option<*mut u8>,
248         size: usize,
249         prot: c_int,
250         flags: c_int,
251         fd: Option<(&AsRawFd, usize)>,
252     ) -> Result<MemoryMapping> {
253         let mut flags = flags;
254         // If addr is provided, set the FIXED flag, and validate addr alignment
255         let addr = match addr {
256             Some(addr) => {
257                 if (addr as usize) % pagesize() != 0 {
258                     return Err(Error::NotPageAligned);
259                 }
260                 flags |= libc::MAP_FIXED;
261                 addr as *mut libc::c_void
262             }
263             None => null_mut(),
264         };
265         // If fd is provided, validate fd offset is within bounds
266         let (fd, offset) = match fd {
267             Some((fd, offset)) => {
268                 if offset > libc::off_t::max_value() as usize {
269                     return Err(Error::InvalidOffset);
270                 }
271                 (fd.as_raw_fd(), offset as libc::off_t)
272             }
273             None => (-1, 0),
274         };
275         let addr = libc::mmap(addr, size, prot, flags, fd, offset);
276         if addr == libc::MAP_FAILED {
277             return Err(Error::SystemCallFailed(errno::Error::last()));
278         }
279         // This is safe because we call madvise with a valid address and size, and we check the
280         // return value. We only warn about an error because failure here is not fatal to the mmap.
281         if libc::madvise(addr, size, libc::MADV_DONTDUMP) == -1 {
282             warn!(
283                 "failed madvise(MADV_DONTDUMP) on mmap: {}",
284                 errno::Error::last()
285             );
286         }
287         Ok(MemoryMapping {
288             addr: addr as *mut u8,
289             size,
290         })
291     }
292 
293     /// Returns a pointer to the beginning of the memory region. Should only be
294     /// used for passing this region to ioctls for setting guest memory.
as_ptr(&self) -> *mut u8295     pub fn as_ptr(&self) -> *mut u8 {
296         self.addr
297     }
298 
299     /// Returns the size of the memory region in bytes.
size(&self) -> usize300     pub fn size(&self) -> usize {
301         self.size
302     }
303 
304     /// Calls msync with MS_SYNC on the mapping.
msync(&self) -> Result<()>305     pub fn msync(&self) -> Result<()> {
306         // This is safe since we use the exact address and length of a known
307         // good memory mapping.
308         let ret = unsafe {
309             libc::msync(
310                 self.as_ptr() as *mut libc::c_void,
311                 self.size(),
312                 libc::MS_SYNC,
313             )
314         };
315         if ret == -1 {
316             return Err(Error::SystemCallFailed(errno::Error::last()));
317         }
318         Ok(())
319     }
320 
321     /// Writes a slice to the memory region at the specified offset.
322     /// Returns the number of bytes written.  The number of bytes written can
323     /// be less than the length of the slice if there isn't enough room in the
324     /// memory region.
325     ///
326     /// # Examples
327     /// * Write a slice at offset 256.
328     ///
329     /// ```
330     /// #   use sys_util::MemoryMapping;
331     /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
332     ///     let res = mem_map.write_slice(&[1,2,3,4,5], 256);
333     ///     assert!(res.is_ok());
334     ///     assert_eq!(res.unwrap(), 5);
335     /// ```
write_slice(&self, buf: &[u8], offset: usize) -> Result<usize>336     pub fn write_slice(&self, buf: &[u8], offset: usize) -> Result<usize> {
337         match self.size.checked_sub(offset) {
338             Some(size_past_offset) => {
339                 let bytes_copied = min(size_past_offset, buf.len());
340                 // The bytes_copied equation above ensures we don't copy bytes out of range of
341                 // either buf or this slice. We also know that the buffers do not overlap because
342                 // slices can never occupy the same memory as a volatile slice.
343                 unsafe {
344                     copy_nonoverlapping(buf.as_ptr(), self.as_ptr().add(offset), bytes_copied);
345                 }
346                 Ok(bytes_copied)
347             }
348             None => Err(Error::InvalidAddress),
349         }
350     }
351 
352     /// Reads to a slice from the memory region at the specified offset.
353     /// Returns the number of bytes read.  The number of bytes read can
354     /// be less than the length of the slice if there isn't enough room in the
355     /// memory region.
356     ///
357     /// # Examples
358     /// * Read a slice of size 16 at offset 256.
359     ///
360     /// ```
361     /// #   use sys_util::MemoryMapping;
362     /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
363     ///     let buf = &mut [0u8; 16];
364     ///     let res = mem_map.read_slice(buf, 256);
365     ///     assert!(res.is_ok());
366     ///     assert_eq!(res.unwrap(), 16);
367     /// ```
read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize>368     pub fn read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize> {
369         match self.size.checked_sub(offset) {
370             Some(size_past_offset) => {
371                 let bytes_copied = min(size_past_offset, buf.len());
372                 // The bytes_copied equation above ensures we don't copy bytes out of range of
373                 // either buf or this slice. We also know that the buffers do not overlap because
374                 // slices can never occupy the same memory as a volatile slice.
375                 unsafe {
376                     copy_nonoverlapping(
377                         self.as_ptr().add(offset) as *const u8,
378                         buf.as_mut_ptr(),
379                         bytes_copied,
380                     );
381                 }
382                 Ok(bytes_copied)
383             }
384             None => Err(Error::InvalidAddress),
385         }
386     }
387 
388     /// Writes an object to the memory region at the specified offset.
389     /// Returns Ok(()) if the object fits, or Err if it extends past the end.
390     ///
391     /// # Examples
392     /// * Write a u64 at offset 16.
393     ///
394     /// ```
395     /// #   use sys_util::MemoryMapping;
396     /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
397     ///     let res = mem_map.write_obj(55u64, 16);
398     ///     assert!(res.is_ok());
399     /// ```
write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()>400     pub fn write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()> {
401         self.range_end(offset, size_of::<T>())?;
402         // This is safe because we checked the bounds above.
403         unsafe {
404             write_unaligned(self.as_ptr().add(offset) as *mut T, val);
405         }
406         Ok(())
407     }
408 
409     /// Reads on object from the memory region at the given offset.
410     /// Reading from a volatile area isn't strictly safe as it could change
411     /// mid-read.  However, as long as the type T is plain old data and can
412     /// handle random initialization, everything will be OK.
413     ///
414     /// # Examples
415     /// * Read a u64 written to offset 32.
416     ///
417     /// ```
418     /// #   use sys_util::MemoryMapping;
419     /// #   let mut mem_map = MemoryMapping::new(1024).unwrap();
420     ///     let res = mem_map.write_obj(55u64, 32);
421     ///     assert!(res.is_ok());
422     ///     let num: u64 = mem_map.read_obj(32).unwrap();
423     ///     assert_eq!(55, num);
424     /// ```
read_obj<T: DataInit>(&self, offset: usize) -> Result<T>425     pub fn read_obj<T: DataInit>(&self, offset: usize) -> Result<T> {
426         self.range_end(offset, size_of::<T>())?;
427         // This is safe because by definition Copy types can have their bits set arbitrarily and
428         // still be valid.
429         unsafe {
430             Ok(read_unaligned(
431                 self.as_ptr().add(offset) as *const u8 as *const T
432             ))
433         }
434     }
435 
436     /// Reads data from a file descriptor and writes it to guest memory.
437     ///
438     /// # Arguments
439     /// * `mem_offset` - Begin writing memory at this offset.
440     /// * `src` - Read from `src` to memory.
441     /// * `count` - Read `count` bytes from `src` to memory.
442     ///
443     /// # Examples
444     ///
445     /// * Read bytes from /dev/urandom
446     ///
447     /// ```
448     /// # use sys_util::MemoryMapping;
449     /// # use std::fs::File;
450     /// # use std::path::Path;
451     /// # fn test_read_random() -> Result<u32, ()> {
452     /// #     let mut mem_map = MemoryMapping::new(1024).unwrap();
453     ///       let mut file = File::open(Path::new("/dev/urandom")).map_err(|_| ())?;
454     ///       mem_map.read_to_memory(32, &mut file, 128).map_err(|_| ())?;
455     ///       let rand_val: u32 =  mem_map.read_obj(40).map_err(|_| ())?;
456     /// #     Ok(rand_val)
457     /// # }
458     /// ```
read_to_memory( &self, mut mem_offset: usize, src: &AsRawFd, mut count: usize, ) -> Result<()>459     pub fn read_to_memory(
460         &self,
461         mut mem_offset: usize,
462         src: &AsRawFd,
463         mut count: usize,
464     ) -> Result<()> {
465         self.range_end(mem_offset, count)
466             .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
467         while count > 0 {
468             // The check above ensures that no memory outside this slice will get accessed by this
469             // read call.
470             match unsafe {
471                 read(
472                     src.as_raw_fd(),
473                     self.as_ptr().add(mem_offset) as *mut c_void,
474                     count,
475                 )
476             } {
477                 0 => {
478                     return Err(Error::ReadToMemory(io::Error::from(
479                         io::ErrorKind::UnexpectedEof,
480                     )))
481                 }
482                 r if r < 0 => return Err(Error::ReadToMemory(io::Error::last_os_error())),
483                 ret => {
484                     let bytes_read = ret as usize;
485                     match count.checked_sub(bytes_read) {
486                         Some(count_remaining) => count = count_remaining,
487                         None => break,
488                     }
489                     mem_offset += ret as usize;
490                 }
491             }
492         }
493         Ok(())
494     }
495 
496     /// Writes data from memory to a file descriptor.
497     ///
498     /// # Arguments
499     /// * `mem_offset` - Begin reading memory from this offset.
500     /// * `dst` - Write from memory to `dst`.
501     /// * `count` - Read `count` bytes from memory to `src`.
502     ///
503     /// # Examples
504     ///
505     /// * Write 128 bytes to /dev/null
506     ///
507     /// ```
508     /// # use sys_util::MemoryMapping;
509     /// # use std::fs::File;
510     /// # use std::path::Path;
511     /// # fn test_write_null() -> Result<(), ()> {
512     /// #     let mut mem_map = MemoryMapping::new(1024).unwrap();
513     ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
514     ///       mem_map.write_from_memory(32, &mut file, 128).map_err(|_| ())?;
515     /// #     Ok(())
516     /// # }
517     /// ```
write_from_memory( &self, mut mem_offset: usize, dst: &AsRawFd, mut count: usize, ) -> Result<()>518     pub fn write_from_memory(
519         &self,
520         mut mem_offset: usize,
521         dst: &AsRawFd,
522         mut count: usize,
523     ) -> Result<()> {
524         self.range_end(mem_offset, count)
525             .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
526         while count > 0 {
527             // The check above ensures that no memory outside this slice will get accessed by this
528             // write call.
529             match unsafe {
530                 write(
531                     dst.as_raw_fd(),
532                     self.as_ptr().add(mem_offset) as *const c_void,
533                     count,
534                 )
535             } {
536                 0 => {
537                     return Err(Error::WriteFromMemory(io::Error::from(
538                         io::ErrorKind::WriteZero,
539                     )))
540                 }
541                 ret if ret < 0 => return Err(Error::WriteFromMemory(io::Error::last_os_error())),
542                 ret => {
543                     let bytes_written = ret as usize;
544                     match count.checked_sub(bytes_written) {
545                         Some(count_remaining) => count = count_remaining,
546                         None => break,
547                     }
548                     mem_offset += ret as usize;
549                 }
550             }
551         }
552         Ok(())
553     }
554 
555     /// Uses madvise to tell the kernel to remove the specified range.  Subsequent reads
556     /// to the pages in the range will return zero bytes.
remove_range(&self, mem_offset: usize, count: usize) -> Result<()>557     pub fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
558         self.range_end(mem_offset, count)
559             .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
560         let ret = unsafe {
561             // madvising away the region is the same as the guest changing it.
562             // Next time it is read, it may return zero pages.
563             libc::madvise(
564                 (self.addr as usize + mem_offset) as *mut _,
565                 count,
566                 libc::MADV_REMOVE,
567             )
568         };
569         if ret < 0 {
570             Err(Error::InvalidRange(mem_offset, count, self.size()))
571         } else {
572             Ok(())
573         }
574     }
575 
576     // Check that offset+count is valid and return the sum.
range_end(&self, offset: usize, count: usize) -> Result<usize>577     fn range_end(&self, offset: usize, count: usize) -> Result<usize> {
578         let mem_end = offset.checked_add(count).ok_or(Error::InvalidAddress)?;
579         if mem_end > self.size() {
580             return Err(Error::InvalidAddress);
581         }
582         Ok(mem_end)
583     }
584 }
585 
586 impl VolatileMemory for MemoryMapping {
get_slice(&self, offset: u64, count: u64) -> VolatileMemoryResult<VolatileSlice>587     fn get_slice(&self, offset: u64, count: u64) -> VolatileMemoryResult<VolatileSlice> {
588         let mem_end = calc_offset(offset, count)?;
589         if mem_end > self.size as u64 {
590             return Err(VolatileMemoryError::OutOfBounds { addr: mem_end });
591         }
592 
593         // Safe because we checked that offset + count was within our range and we only ever hand
594         // out volatile accessors.
595         Ok(unsafe { VolatileSlice::new((self.addr as usize + offset as usize) as *mut _, count) })
596     }
597 }
598 
599 impl Drop for MemoryMapping {
drop(&mut self)600     fn drop(&mut self) {
601         // This is safe because we mmap the area at addr ourselves, and nobody
602         // else is holding a reference to it.
603         unsafe {
604             libc::munmap(self.addr as *mut libc::c_void, self.size);
605         }
606     }
607 }
608 
609 /// Tracks Fixed Memory Maps within an anonymous memory-mapped fixed-sized arena
610 /// in the current process.
611 pub struct MemoryMappingArena {
612     addr: *mut u8,
613     size: usize,
614     // When doing in-place swaps of MemoryMappings, the BTreeMap returns a owned
615     // instance of the old MemoryMapping. When the old MemoryMapping falls out
616     // of scope, it calls munmap on the same region as the new MemoryMapping
617     // that was just mapped in. To avoid accidentally munmapping the new,
618     // MemoryMapping, all mappings are wrapped in a ManuallyDrop, and then
619     // "forgotten" when removed from the BTreeMap
620     maps: BTreeMap<usize, ManuallyDrop<MemoryMapping>>,
621 }
622 
623 // Send and Sync aren't automatically inherited for the raw address pointer.
624 // Accessing that pointer is only done through the stateless interface which
625 // allows the object to be shared by multiple threads without a decrease in
626 // safety.
627 unsafe impl Send for MemoryMappingArena {}
628 unsafe impl Sync for MemoryMappingArena {}
629 
630 impl MemoryMappingArena {
631     /// Creates an mmap arena of `size` bytes.
632     ///
633     /// # Arguments
634     /// * `size` - Size of memory region in bytes.
new(size: usize) -> Result<MemoryMappingArena>635     pub fn new(size: usize) -> Result<MemoryMappingArena> {
636         // Reserve the arena's memory using an anonymous read-only mmap.
637         // The actual MemoryMapping object is forgotten, with
638         // MemoryMappingArena manually calling munmap on drop.
639         let mmap = MemoryMapping::new_protection(size, Protection::none().set_read())?;
640         let addr = mmap.as_ptr();
641         let size = mmap.size();
642         std::mem::forget(mmap);
643         Ok(MemoryMappingArena {
644             addr,
645             size,
646             maps: BTreeMap::new(),
647         })
648     }
649 
650     /// Anonymously maps `size` bytes at `offset` bytes from the start of the arena.
651     /// `offset` must be page aligned.
652     ///
653     /// # Arguments
654     /// * `offset` - Page aligned offset into the arena in bytes.
655     /// * `size` - Size of memory region in bytes.
656     /// * `fd` - File descriptor to mmap from.
add_anon(&mut self, offset: usize, size: usize) -> Result<()>657     pub fn add_anon(&mut self, offset: usize, size: usize) -> Result<()> {
658         self.try_add(offset, size, Protection::read_write(), None)
659     }
660 
661     /// Maps `size` bytes from the start of the given `fd` at `offset` bytes from
662     /// the start of the arena. `offset` must be page aligned.
663     ///
664     /// # Arguments
665     /// * `offset` - Page aligned offset into the arena in bytes.
666     /// * `size` - Size of memory region in bytes.
667     /// * `fd` - File descriptor to mmap from.
add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawFd) -> Result<()>668     pub fn add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawFd) -> Result<()> {
669         self.add_fd_offset(offset, size, fd, 0)
670     }
671 
672     /// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`
673     /// at `offset` bytes from the start of the arena. `offset` must be page aligned.
674     ///
675     /// # Arguments
676     /// * `offset` - Page aligned offset into the arena in bytes.
677     /// * `size` - Size of memory region in bytes.
678     /// * `fd` - File descriptor to mmap from.
679     /// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
add_fd_offset( &mut self, offset: usize, size: usize, fd: &dyn AsRawFd, fd_offset: usize, ) -> Result<()>680     pub fn add_fd_offset(
681         &mut self,
682         offset: usize,
683         size: usize,
684         fd: &dyn AsRawFd,
685         fd_offset: usize,
686     ) -> Result<()> {
687         self.add_fd_offset_protection(offset, size, fd, fd_offset, Protection::read_write())
688     }
689 
690     /// Maps `size` bytes starting at `fs_offset` bytes from within the given `fd`
691     /// at `offset` bytes from the start of the arena with `prot` protections.
692     /// `offset` must be page aligned.
693     ///
694     /// # Arguments
695     /// * `offset` - Page aligned offset into the arena in bytes.
696     /// * `size` - Size of memory region in bytes.
697     /// * `fd` - File descriptor to mmap from.
698     /// * `fd_offset` - Offset in bytes from the beginning of `fd` to start the mmap.
699     /// * `prot` - Protection (e.g. readable/writable) of the memory region.
add_fd_offset_protection( &mut self, offset: usize, size: usize, fd: &dyn AsRawFd, fd_offset: usize, prot: Protection, ) -> Result<()>700     pub fn add_fd_offset_protection(
701         &mut self,
702         offset: usize,
703         size: usize,
704         fd: &dyn AsRawFd,
705         fd_offset: usize,
706         prot: Protection,
707     ) -> Result<()> {
708         self.try_add(offset, size, prot, Some((fd, fd_offset)))
709     }
710 
711     /// Helper method that calls appropriate MemoryMapping constructor and adds
712     /// the resulting map into the arena.
try_add( &mut self, offset: usize, size: usize, prot: Protection, fd: Option<(&AsRawFd, usize)>, ) -> Result<()>713     fn try_add(
714         &mut self,
715         offset: usize,
716         size: usize,
717         prot: Protection,
718         fd: Option<(&AsRawFd, usize)>,
719     ) -> Result<()> {
720         self.validate_range(offset, size)?;
721 
722         // This is safe since the range has been validated.
723         let mmap = unsafe {
724             match fd {
725                 Some((fd, fd_offset)) => MemoryMapping::from_fd_offset_protection_fixed(
726                     (self.addr as usize + offset) as *mut u8,
727                     fd,
728                     size,
729                     fd_offset,
730                     prot,
731                 )?,
732                 None => MemoryMapping::new_protection_fixed(
733                     (self.addr as usize + offset) as *mut u8,
734                     size,
735                     prot,
736                 )?,
737             }
738         };
739 
740         self.maps.insert(offset, ManuallyDrop::new(mmap));
741         Ok(())
742     }
743 
744     /// Removes a mapping at `offset` from the start of the arena.
745     /// Returns a boolean indicating if there was a mapping present at `offset`.
746     /// If none was present, this method is a noop.
remove(&mut self, offset: usize) -> Result<bool>747     pub fn remove(&mut self, offset: usize) -> Result<bool> {
748         if let Some(mmap) = self.maps.remove(&offset) {
749             // Instead of munmapping the memory map, leaving an unprotected hole
750             // in the arena, swap this mmap with an anonymous protection.
751             // This is safe since the memory mapping perfectly overlaps with an
752             // existing, known good memory mapping.
753             let mmap = unsafe {
754                 MemoryMapping::new_protection_fixed(
755                     mmap.as_ptr(),
756                     mmap.size(),
757                     Protection::none().set_read(),
758                 )?
759             };
760             self.maps.insert(offset, ManuallyDrop::new(mmap));
761             Ok(true)
762         } else {
763             Ok(false)
764         }
765     }
766 
767     /// Calls msync with MS_SYNC on the mapping at `offset` from the start of
768     /// the arena.
769     /// Returns a boolean indicating if there was a mapping present at `offset`.
770     /// If none was present, this method is a noop.
msync(&self, offset: usize) -> Result<bool>771     pub fn msync(&self, offset: usize) -> Result<bool> {
772         if let Some(mmap) = self.maps.get(&offset) {
773             mmap.msync()?;
774             Ok(true)
775         } else {
776             Ok(false)
777         }
778     }
779 
780     /// Returns a pointer to the beginning of the memory region.  Should only be
781     /// used for passing this region to ioctls for setting guest memory.
as_ptr(&self) -> *mut u8782     pub fn as_ptr(&self) -> *mut u8 {
783         self.addr
784     }
785 
786     /// Returns the size of the memory region in bytes.
size(&self) -> usize787     pub fn size(&self) -> usize {
788         self.size
789     }
790 
791     /// Validates `offset` and `size`.
792     /// Checks that offset..offset+size doesn't overlap with existing mappings.
793     /// Also ensures correct alignment, and checks for any overflow.
794     /// Note: offset..offset+size is considered valid if it _perfectly_ overlaps
795     /// with single other region.
validate_range(&self, offset: usize, size: usize) -> Result<()>796     fn validate_range(&self, offset: usize, size: usize) -> Result<()> {
797         // Ensure offset is page-aligned
798         if offset % pagesize() != 0 {
799             return Err(Error::NotPageAligned);
800         }
801         // Ensure offset + size doesn't overflow
802         let end_offset = offset.checked_add(size).ok_or(Error::InvalidAddress)?;
803         // Ensure offset + size are within the arena bounds
804         if end_offset > self.size {
805             return Err(Error::InvalidAddress);
806         }
807         // Ensure offset..offset+size doesn't overlap with existing regions
808         // Find the offset + size of the first mapping before the desired offset
809         let (prev_offset, prev_size) = match self.maps.range(..offset).rev().next() {
810             Some((offset, mmap)) => (*offset, mmap.size()),
811             None => {
812                 // Empty map
813                 return Ok(());
814             }
815         };
816         if offset == prev_offset {
817             // Perfectly overlapping regions are allowed
818             if size != prev_size {
819                 return Err(Error::Overlapping(offset, size));
820             }
821         } else if offset < (prev_offset + prev_size) {
822             return Err(Error::Overlapping(offset, size));
823         }
824 
825         Ok(())
826     }
827 }
828 
829 impl Drop for MemoryMappingArena {
drop(&mut self)830     fn drop(&mut self) {
831         // This is safe because we mmap the area at addr ourselves, and nobody
832         // else is holding a reference to it.
833         unsafe {
834             libc::munmap(self.addr as *mut libc::c_void, self.size);
835         }
836     }
837 }
838 
839 #[cfg(test)]
840 mod tests {
841     use super::*;
842     use data_model::{VolatileMemory, VolatileMemoryError};
843     use std::os::unix::io::FromRawFd;
844 
845     #[test]
basic_map()846     fn basic_map() {
847         let m = MemoryMapping::new(1024).unwrap();
848         assert_eq!(1024, m.size());
849     }
850 
851     #[test]
map_invalid_size()852     fn map_invalid_size() {
853         let res = MemoryMapping::new(0).unwrap_err();
854         if let Error::SystemCallFailed(e) = res {
855             assert_eq!(e.errno(), libc::EINVAL);
856         } else {
857             panic!("unexpected error: {}", res);
858         }
859     }
860 
861     #[test]
map_invalid_fd()862     fn map_invalid_fd() {
863         let fd = unsafe { std::fs::File::from_raw_fd(-1) };
864         let res = MemoryMapping::from_fd(&fd, 1024).unwrap_err();
865         if let Error::SystemCallFailed(e) = res {
866             assert_eq!(e.errno(), libc::EBADF);
867         } else {
868             panic!("unexpected error: {}", res);
869         }
870     }
871 
872     #[test]
test_write_past_end()873     fn test_write_past_end() {
874         let m = MemoryMapping::new(5).unwrap();
875         let res = m.write_slice(&[1, 2, 3, 4, 5, 6], 0);
876         assert!(res.is_ok());
877         assert_eq!(res.unwrap(), 5);
878     }
879 
880     #[test]
slice_size()881     fn slice_size() {
882         let m = MemoryMapping::new(5).unwrap();
883         let s = m.get_slice(2, 3).unwrap();
884         assert_eq!(s.size(), 3);
885     }
886 
887     #[test]
slice_addr()888     fn slice_addr() {
889         let m = MemoryMapping::new(5).unwrap();
890         let s = m.get_slice(2, 3).unwrap();
891         assert_eq!(s.as_ptr(), unsafe { m.as_ptr().offset(2) });
892     }
893 
894     #[test]
slice_store()895     fn slice_store() {
896         let m = MemoryMapping::new(5).unwrap();
897         let r = m.get_ref(2).unwrap();
898         r.store(9u16);
899         assert_eq!(m.read_obj::<u16>(2).unwrap(), 9);
900     }
901 
902     #[test]
slice_overflow_error()903     fn slice_overflow_error() {
904         let m = MemoryMapping::new(5).unwrap();
905         let res = m.get_slice(std::u64::MAX, 3).unwrap_err();
906         assert_eq!(
907             res,
908             VolatileMemoryError::Overflow {
909                 base: std::u64::MAX,
910                 offset: 3,
911             }
912         );
913     }
914     #[test]
slice_oob_error()915     fn slice_oob_error() {
916         let m = MemoryMapping::new(5).unwrap();
917         let res = m.get_slice(3, 3).unwrap_err();
918         assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
919     }
920 
921     #[test]
from_fd_offset_invalid()922     fn from_fd_offset_invalid() {
923         let fd = unsafe { std::fs::File::from_raw_fd(-1) };
924         let res = MemoryMapping::from_fd_offset(&fd, 4096, (libc::off_t::max_value() as usize) + 1)
925             .unwrap_err();
926         match res {
927             Error::InvalidOffset => {}
928             e => panic!("unexpected error: {}", e),
929         }
930     }
931 
932     #[test]
arena_new()933     fn arena_new() {
934         let m = MemoryMappingArena::new(0x40000).unwrap();
935         assert_eq!(m.size(), 0x40000);
936     }
937 
938     #[test]
arena_add()939     fn arena_add() {
940         let mut m = MemoryMappingArena::new(0x40000).unwrap();
941         assert!(m.add_anon(0, pagesize() * 4).is_ok());
942     }
943 
944     #[test]
arena_remove()945     fn arena_remove() {
946         let mut m = MemoryMappingArena::new(0x40000).unwrap();
947         assert!(m.add_anon(0, pagesize() * 4).is_ok());
948         assert!(m.remove(0).unwrap(), true);
949         assert!(m.remove(0).unwrap(), false);
950     }
951 
952     #[test]
arena_add_overlap_error()953     fn arena_add_overlap_error() {
954         let page = pagesize();
955         let mut m = MemoryMappingArena::new(page * 4).unwrap();
956         assert!(m.add_anon(0, page * 4).is_ok());
957         let res = m.add_anon(page, page).unwrap_err();
958         match res {
959             Error::Overlapping(a, o) => {
960                 assert_eq!((a, o), (page, page));
961             }
962             e => panic!("unexpected error: {}", e),
963         }
964     }
965 
966     #[test]
arena_add_alignment_error()967     fn arena_add_alignment_error() {
968         let mut m = MemoryMappingArena::new(pagesize() * 2).unwrap();
969         assert!(m.add_anon(0, 0x100).is_ok());
970         let res = m.add_anon(pagesize() + 1, 0x100).unwrap_err();
971         match res {
972             Error::NotPageAligned => {}
973             e => panic!("unexpected error: {}", e),
974         }
975     }
976 
977     #[test]
arena_add_oob_error()978     fn arena_add_oob_error() {
979         let mut m = MemoryMappingArena::new(pagesize()).unwrap();
980         let res = m.add_anon(0, pagesize() + 1).unwrap_err();
981         match res {
982             Error::InvalidAddress => {}
983             e => panic!("unexpected error: {}", e),
984         }
985     }
986 }
987