summary refs log tree commit diff
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2019-05-30 18:31:02 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-04 20:29:25 +0000
commit127453d7eccdb6a903d0855fabb8f0935be90882 (patch)
tree65bd9f0b4c6b2a98c60bb2580949a93209c0f639
parent6a0bfb037a109030b69feb9dec4a546548636940 (diff)
downloadcrosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar.gz
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar.bz2
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar.lz
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar.xz
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.tar.zst
crosvm-127453d7eccdb6a903d0855fabb8f0935be90882.zip
eliminate mut from non-mut references
This manifested itself in a couple places that were turning shared
memory buffers into slices for the purposes of passing these slices to
`Read` and `Write` trait methods.

However, this required the removal of the methods that took `Read` and
`Write` instances. This was a convenient interface but impossible to
implement safely because making slices from raw pointers without
enforcing safety guarantees causes undefined behaviour in Rust. It turns
out lots of code in crosvm was using these interfaces indirectly, which
explains why this CL touches so much.

TEST=crosvm run
BUG=chromium:938767

Change-Id: I4ff40c98da6ed08a4a42f4c31f0717f81b1c5863
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1636685
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Zach Reizner <zachr@chromium.org>
-rw-r--r--Cargo.lock1
-rw-r--r--arch/src/lib.rs4
-rwxr-xr-xbin/clippy2
-rw-r--r--data_model/src/volatile_memory.rs149
-rw-r--r--devices/src/pci/ac97_bus_master.rs11
-rw-r--r--devices/src/virtio/block.rs108
-rw-r--r--devices/src/virtio/input/mod.rs11
-rw-r--r--devices/src/virtio/rng.rs6
-rw-r--r--devices/src/virtio/wl.rs9
-rw-r--r--kernel_loader/src/lib.rs46
-rw-r--r--qcow/Cargo.toml1
-rw-r--r--qcow/src/qcow.rs140
-rw-r--r--sys_util/src/file_traits.rs84
-rw-r--r--sys_util/src/guest_memory.rs23
-rw-r--r--sys_util/src/lib.rs2
-rw-r--r--sys_util/src/mmap.rs196
-rw-r--r--sys_util/src/shm.rs59
-rw-r--r--x86_64/src/bzimage.rs3
-rw-r--r--x86_64/src/lib.rs6
-rw-r--r--x86_64/src/mptable.rs28
20 files changed, 522 insertions, 367 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 44fa861..8446532 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -395,6 +395,7 @@ name = "qcow"
 version = "0.1.0"
 dependencies = [
  "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "data_model 0.1.0",
  "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
  "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "sys_util 0.1.0",
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 1f26cb4..91e7ee4 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -312,7 +312,7 @@ pub fn load_image<F>(
     max_size: u64,
 ) -> Result<usize, LoadImageError>
 where
-    F: Read + Seek,
+    F: Read + Seek + AsRawFd,
 {
     let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
 
@@ -354,7 +354,7 @@ pub fn load_image_high<F>(
     align: u64,
 ) -> Result<(GuestAddress, usize), LoadImageError>
 where
-    F: Read + Seek,
+    F: Read + Seek + AsRawFd,
 {
     if !align.is_power_of_two() {
         return Err(LoadImageError::BadAlignment(align));
diff --git a/bin/clippy b/bin/clippy
index a19b6eb..f01e801 100755
--- a/bin/clippy
+++ b/bin/clippy
@@ -21,7 +21,7 @@ SUPPRESS=(
     # We don't care about these lints. Okay to remain suppressed globally.
     blacklisted_name
     cast_lossless
-    cyclomatic_complexity
+    cognitive_complexity
     enum_variant_names
     identity_op
     len_without_is_empty
diff --git a/data_model/src/volatile_memory.rs b/data_model/src/volatile_memory.rs
index 9bdc0f4..6ce230b 100644
--- a/data_model/src/volatile_memory.rs
+++ b/data_model/src/volatile_memory.rs
@@ -21,14 +21,10 @@
 
 use std::cmp::min;
 use std::fmt::{self, Display};
-use std::io::Result as IoResult;
-use std::io::{Read, Write};
 use std::marker::PhantomData;
 use std::mem::size_of;
-use std::ptr::copy;
-use std::ptr::{null_mut, read_volatile, write_volatile};
+use std::ptr::{copy, null_mut, read_volatile, write_bytes, write_volatile};
 use std::result;
-use std::slice::{from_raw_parts, from_raw_parts_mut};
 use std::{isize, usize};
 
 use crate::DataInit;
@@ -178,6 +174,31 @@ impl<'a> VolatileSlice<'a> {
         unsafe { Ok(VolatileSlice::new(new_addr as *mut u8, new_size)) }
     }
 
+    /// Sets each byte of this slice with the given byte, similar to `memset`.
+    ///
+    /// The bytes of this slice are accessed in an arbitray order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use data_model::VolatileMemory;
+    /// # fn test_write_45() -> Result<(), ()> {
+    /// let mut mem = [0u8; 32];
+    /// let mem_ref = &mut mem[..];
+    /// let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
+    /// vslice.write_bytes(45);
+    /// for &mut v in mem_ref {
+    ///     assert_eq!(v, 45);
+    /// }
+    /// # Ok(())
+    /// # }
+    pub fn write_bytes(&self, value: u8) {
+        // Safe because the memory is valid and needs only byte alignment.
+        unsafe {
+            write_bytes(self.as_ptr(), value, self.size as usize);
+        }
+    }
+
     /// Copies `self.size()` or `buf.len()` times the size of `T` bytes, whichever is smaller, to
     /// `buf`.
     ///
@@ -270,124 +291,6 @@ impl<'a> VolatileSlice<'a> {
             }
         }
     }
-
-    /// Attempt to write all data from memory to a writable object and returns how many bytes were
-    /// actually written on success.
-    ///
-    /// # Arguments
-    /// * `w` - Write from memory to `w`.
-    ///
-    /// # Examples
-    ///
-    /// * Write some bytes to /dev/null
-    ///
-    /// ```
-    /// # use std::fs::File;
-    /// # use std::path::Path;
-    /// # use data_model::VolatileMemory;
-    /// # fn test_write_null() -> Result<(), ()> {
-    /// #     let mut mem = [0u8; 32];
-    /// #     let mem_ref = &mut mem[..];
-    /// #     let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
-    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
-    ///       vslice.write_to(&mut file).map_err(|_| ())?;
-    /// #     Ok(())
-    /// # }
-    /// ```
-    pub fn write_to<T: Write>(&self, w: &mut T) -> IoResult<usize> {
-        w.write(unsafe { self.as_slice() })
-    }
-
-    /// Writes all data from memory to a writable object via `Write::write_all`.
-    ///
-    /// # Arguments
-    /// * `w` - Write from memory to `w`.
-    ///
-    /// # Examples
-    ///
-    /// * Write some bytes to /dev/null
-    ///
-    /// ```
-    /// # use std::fs::File;
-    /// # use std::path::Path;
-    /// # use data_model::VolatileMemory;
-    /// # fn test_write_null() -> Result<(), ()> {
-    /// #     let mut mem = [0u8; 32];
-    /// #     let mem_ref = &mut mem[..];
-    /// #     let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
-    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
-    ///       vslice.write_all_to(&mut file).map_err(|_| ())?;
-    /// #     Ok(())
-    /// # }
-    /// ```
-    pub fn write_all_to<T: Write>(&self, w: &mut T) -> IoResult<()> {
-        w.write_all(unsafe { self.as_slice() })
-    }
-
-    /// Reads up to this slice's size to memory from a readable object and returns how many bytes
-    /// were actually read on success.
-    ///
-    /// # Arguments
-    /// * `r` - Read to `r` to memory.
-    ///
-    /// # Examples
-    ///
-    /// * Read some bytes to /dev/null
-    ///
-    /// ```
-    /// # use std::fs::File;
-    /// # use std::path::Path;
-    /// # use data_model::VolatileMemory;
-    /// # fn test_write_null() -> Result<(), ()> {
-    /// #     let mut mem = [0u8; 32];
-    /// #     let mem_ref = &mut mem[..];
-    /// #     let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
-    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
-    ///       vslice.read_from(&mut file).map_err(|_| ())?;
-    /// #     Ok(())
-    /// # }
-    /// ```
-    pub fn read_from<T: Read>(&self, r: &mut T) -> IoResult<usize> {
-        r.read(unsafe { self.as_mut_slice() })
-    }
-
-    /// Read exactly this slice's size into memory from to a readable object via `Read::read_exact`.
-    ///
-    /// # Arguments
-    /// * `r` - Read to `r` to memory.
-    ///
-    /// # Examples
-    ///
-    /// * Read some bytes to /dev/null
-    ///
-    /// ```
-    /// # use std::fs::File;
-    /// # use std::path::Path;
-    /// # use data_model::VolatileMemory;
-    /// # fn test_write_null() -> Result<(), ()> {
-    /// #     let mut mem = [0u8; 32];
-    /// #     let mem_ref = &mut mem[..];
-    /// #     let vslice = mem_ref.get_slice(0, 32).map_err(|_| ())?;
-    ///       let mut file = File::open(Path::new("/dev/null")).map_err(|_| ())?;
-    ///       vslice.read_from(&mut file).map_err(|_| ())?;
-    /// #     Ok(())
-    /// # }
-    /// ```
-    pub fn read_exact_from<T: Read>(&self, r: &mut T) -> IoResult<()> {
-        r.read_exact(unsafe { self.as_mut_slice() })
-    }
-
-    // These function are private and only used for the read/write functions. It is not valid in
-    // general to take slices of volatile memory.
-    unsafe fn as_slice(&self) -> &[u8] {
-        from_raw_parts(self.addr, self.size as usize)
-    }
-
-    // TODO(zachr) - refactor this so the mut from non-mut isn't necessary (bug: 938767)
-    #[allow(clippy::mut_from_ref)]
-    unsafe fn as_mut_slice(&self) -> &mut [u8] {
-        from_raw_parts_mut(self.addr, self.size as usize)
-    }
 }
 
 impl<'a> VolatileMemory for VolatileSlice<'a> {
diff --git a/devices/src/pci/ac97_bus_master.rs b/devices/src/pci/ac97_bus_master.rs
index 47be8c4..bde5c90 100644
--- a/devices/src/pci/ac97_bus_master.rs
+++ b/devices/src/pci/ac97_bus_master.rs
@@ -143,8 +143,6 @@ enum CaptureError {
     ReadingGuestError(GuestMemoryError),
     // Failure to get an buffer from the stream.
     StreamError(Box<dyn Error>),
-    // Failure reading to the audio input.
-    ReadingInput(std::io::Error),
 }
 
 impl std::error::Error for CaptureError {}
@@ -156,7 +154,6 @@ impl Display for CaptureError {
         match self {
             ReadingGuestError(e) => write!(f, "Failed to read guest memory: {}.", e),
             StreamError(e) => write!(f, "Failed to get a buffer from the stream: {}", e),
-            ReadingInput(e) => write!(f, "Failed to read audio input: {}.", e),
         }
     }
 }
@@ -653,9 +650,7 @@ fn play_buffer(
     let func_regs = regs.func_regs_mut(Ac97Function::Output);
     let buffer_len = func_regs.picb * 2;
     if let Some(buffer) = next_guest_buffer(func_regs, mem)? {
-        buffer
-            .write_to(out_buffer)
-            .map_err(PlaybackError::WritingOutput)?;
+        out_buffer.copy_cb(buffer.size() as usize, |out| buffer.copy_to(out));
     } else {
         let zeros = vec![0u8; buffer_len as usize];
         out_buffer
@@ -732,9 +727,7 @@ fn capture_buffer(
     }
     let func_regs = regs.func_regs_mut(Ac97Function::Input);
     if let Some(buffer) = next_guest_buffer(func_regs, mem)? {
-        buffer
-            .read_from(in_buffer)
-            .map_err(CaptureError::ReadingInput)?;
+        in_buffer.copy_cb(buffer.size() as usize, |inb| buffer.copy_from(inb))
     }
     Ok(())
 }
diff --git a/devices/src/virtio/block.rs b/devices/src/virtio/block.rs
index 17a5723..59cc51a 100644
--- a/devices/src/virtio/block.rs
+++ b/devices/src/virtio/block.rs
@@ -4,7 +4,7 @@
 
 use std::cmp;
 use std::fmt::{self, Display};
-use std::io::{self, Read, Seek, SeekFrom, Write};
+use std::io::{self, Seek, SeekFrom, Write};
 use std::mem::{size_of, size_of_val};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::result;
@@ -18,11 +18,11 @@ use sync::Mutex;
 use sys_util::Error as SysError;
 use sys_util::Result as SysResult;
 use sys_util::{
-    error, info, warn, EventFd, FileSetLen, FileSync, GuestAddress, GuestMemory, GuestMemoryError,
-    PollContext, PollToken, PunchHole, TimerFd, WriteZeroes,
+    error, info, warn, EventFd, FileReadWriteVolatile, FileSetLen, FileSync, GuestAddress,
+    GuestMemory, GuestMemoryError, PollContext, PollToken, PunchHole, TimerFd, WriteZeroes,
 };
 
-use data_model::{DataInit, Le16, Le32, Le64};
+use data_model::{DataInit, Le16, Le32, Le64, VolatileMemory, VolatileMemoryError};
 use msg_socket::{MsgReceiver, MsgSender};
 use vm_control::{DiskControlCommand, DiskControlResponseSocket, DiskControlResult};
 
@@ -116,8 +116,14 @@ const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;
 // Safe because it only has data and has no implicit padding.
 unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
 
-pub trait DiskFile: FileSetLen + FileSync + PunchHole + Read + Seek + Write + WriteZeroes {}
-impl<D: FileSetLen + FileSync + PunchHole + Read + Seek + Write + WriteZeroes> DiskFile for D {}
+pub trait DiskFile:
+    FileSetLen + FileSync + FileReadWriteVolatile + PunchHole + Seek + WriteZeroes
+{
+}
+impl<D: FileSetLen + FileSync + PunchHole + FileReadWriteVolatile + Seek + WriteZeroes> DiskFile
+    for D
+{
+}
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 enum RequestType {
@@ -215,22 +221,34 @@ fn discard_write_zeroes_segment(
 enum ExecuteError {
     /// Error arming the flush timer.
     Flush(io::Error),
-    Read {
+    ReadVolatile {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        volatile_memory_error: VolatileMemoryError,
+    },
+    ReadIo {
         addr: GuestAddress,
         length: u32,
         sector: u64,
-        guestmemerr: GuestMemoryError,
+        io_error: io::Error,
     },
     Seek {
         ioerr: io::Error,
         sector: u64,
     },
     TimerFd(SysError),
-    Write {
+    WriteVolatile {
         addr: GuestAddress,
         length: u32,
         sector: u64,
-        guestmemerr: GuestMemoryError,
+        volatile_memory_error: VolatileMemoryError,
+    },
+    WriteIo {
+        addr: GuestAddress,
+        length: u32,
+        sector: u64,
+        io_error: io::Error,
     },
     DiscardWriteZeroes {
         ioerr: Option<io::Error>,
@@ -251,27 +269,47 @@ impl Display for ExecuteError {
 
         match self {
             Flush(e) => write!(f, "failed to flush: {}", e),
-            Read {
+            ReadVolatile {
+                addr,
+                length,
+                sector,
+                volatile_memory_error,
+            } => write!(
+                f,
+                "memory error reading {} bytes from sector {} to address {}: {}",
+                length, sector, addr, volatile_memory_error,
+            ),
+            ReadIo {
                 addr,
                 length,
                 sector,
-                guestmemerr,
+                io_error,
             } => write!(
                 f,
-                "failed to read {} bytes from sector {} to address {}: {}",
-                length, sector, addr, guestmemerr,
+                "io error reading {} bytes from sector {} to address {}: {}",
+                length, sector, addr, io_error,
             ),
             Seek { ioerr, sector } => write!(f, "failed to seek to sector {}: {}", sector, ioerr),
             TimerFd(e) => write!(f, "{}", e),
-            Write {
+            WriteVolatile {
+                addr,
+                length,
+                sector,
+                volatile_memory_error,
+            } => write!(
+                f,
+                "memory error writing {} bytes from address {} to sector {}: {}",
+                length, addr, sector, volatile_memory_error,
+            ),
+            WriteIo {
                 addr,
                 length,
                 sector,
-                guestmemerr,
+                io_error,
             } => write!(
                 f,
-                "failed to write {} bytes from address {} to sector {}: {}",
-                length, addr, sector, guestmemerr,
+                "io error writing {} bytes from address {} to sector {}: {}",
+                length, addr, sector, io_error,
             ),
             DiscardWriteZeroes {
                 ioerr: Some(ioerr),
@@ -304,10 +342,12 @@ impl ExecuteError {
     fn status(&self) -> u8 {
         match self {
             ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
-            ExecuteError::Read { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::ReadIo { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::ReadVolatile { .. } => VIRTIO_BLK_S_IOERR,
             ExecuteError::Seek { .. } => VIRTIO_BLK_S_IOERR,
             ExecuteError::TimerFd(_) => VIRTIO_BLK_S_IOERR,
-            ExecuteError::Write { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::WriteIo { .. } => VIRTIO_BLK_S_IOERR,
+            ExecuteError::WriteVolatile { .. } => VIRTIO_BLK_S_IOERR,
             ExecuteError::DiscardWriteZeroes { .. } => VIRTIO_BLK_S_IOERR,
             ExecuteError::ReadOnly { .. } => VIRTIO_BLK_S_IOERR,
             ExecuteError::OutOfRange { .. } => VIRTIO_BLK_S_IOERR,
@@ -504,12 +544,20 @@ impl Request {
                         ioerr: e,
                         sector: self.sector,
                     })?;
-                mem.read_to_memory(self.data_addr, disk, self.data_len as usize)
-                    .map_err(|e| ExecuteError::Read {
+                let mem_slice = mem
+                    .get_slice(self.data_addr.0, self.data_len as u64)
+                    .map_err(|volatile_memory_error| ExecuteError::ReadVolatile {
                         addr: self.data_addr,
                         length: self.data_len,
                         sector: self.sector,
-                        guestmemerr: e,
+                        volatile_memory_error,
+                    })?;
+                disk.read_exact_volatile(mem_slice)
+                    .map_err(|io_error| ExecuteError::ReadIo {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        io_error,
                     })?;
                 return Ok(self.data_len);
             }
@@ -524,12 +572,20 @@ impl Request {
                         ioerr: e,
                         sector: self.sector,
                     })?;
-                mem.write_from_memory(self.data_addr, disk, self.data_len as usize)
-                    .map_err(|e| ExecuteError::Write {
+                let mem_slice = mem
+                    .get_slice(self.data_addr.0, self.data_len as u64)
+                    .map_err(|volatile_memory_error| ExecuteError::WriteVolatile {
+                        addr: self.data_addr,
+                        length: self.data_len,
+                        sector: self.sector,
+                        volatile_memory_error,
+                    })?;
+                disk.write_all_volatile(mem_slice)
+                    .map_err(|io_error| ExecuteError::WriteIo {
                         addr: self.data_addr,
                         length: self.data_len,
                         sector: self.sector,
-                        guestmemerr: e,
+                        io_error,
                     })?;
                 if !*flush_timer_armed {
                     flush_timer
diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs
index 3a2c391..205d82f 100644
--- a/devices/src/virtio/input/mod.rs
+++ b/devices/src/virtio/input/mod.rs
@@ -417,11 +417,10 @@ impl<T: EventSource> Worker<T> {
                     let avail_events_size =
                         self.event_source.available_events_count() * virtio_input_event::EVENT_SIZE;
                     let len = min(avail_desc.len as usize, avail_events_size);
-                    if let Err(e) = self.guest_memory.read_to_memory(
-                        avail_desc.addr,
-                        &mut self.event_source,
-                        len,
-                    ) {
+                    if let Err(e) =
+                        self.guest_memory
+                            .read_to_memory(avail_desc.addr, &self.event_source, len)
+                    {
                         // Read is guaranteed to succeed here, so the only possible failure would be
                         // writing outside the guest memory region, which would mean the address and
                         // length given in the queue descriptor are wrong.
@@ -453,7 +452,7 @@ impl<T: EventSource> Worker<T> {
                 );
             } else {
                 self.guest_memory
-                    .write_from_memory(avail_desc.addr, &mut self.event_source, len)
+                    .write_from_memory(avail_desc.addr, &self.event_source, len)
                     .map_err(InputError::EventsWriteError)?;
             }
 
diff --git a/devices/src/virtio/rng.rs b/devices/src/virtio/rng.rs
index 8338119..19f83bc 100644
--- a/devices/src/virtio/rng.rs
+++ b/devices/src/virtio/rng.rs
@@ -57,11 +57,7 @@ impl Worker {
                 // Fill the read with data from the random device on the host.
                 if self
                     .mem
-                    .read_to_memory(
-                        avail_desc.addr,
-                        &mut self.random_file,
-                        avail_desc.len as usize,
-                    )
+                    .read_to_memory(avail_desc.addr, &self.random_file, avail_desc.len as usize)
                     .is_ok()
                 {
                     len = avail_desc.len;
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 9919bac..dd8ce86 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -62,8 +62,9 @@ use resources::GpuMemoryDesc;
 #[cfg(feature = "wl-dmabuf")]
 use sys_util::ioctl_iow_nr;
 use sys_util::{
-    error, pipe, round_up_to_page_size, warn, Error, EventFd, FileFlags, GuestAddress, GuestMemory,
-    GuestMemoryError, PollContext, PollToken, Result, ScmSocket, SharedMemory,
+    error, pipe, round_up_to_page_size, warn, Error, EventFd, FileFlags, FileReadWriteVolatile,
+    GuestAddress, GuestMemory, GuestMemoryError, PollContext, PollToken, Result, ScmSocket,
+    SharedMemory,
 };
 
 #[cfg(feature = "wl-dmabuf")]
@@ -911,7 +912,9 @@ impl WlVfd {
             if !fds.is_empty() {
                 return Ok(WlResp::InvalidType);
             }
-            data.write_all_to(local_pipe).map_err(WlError::WritePipe)?;
+            local_pipe
+                .write_volatile(data)
+                .map_err(WlError::WritePipe)?;
             Ok(WlResp::Ok)
         } else {
             Ok(WlResp::InvalidType)
diff --git a/kernel_loader/src/lib.rs b/kernel_loader/src/lib.rs
index c11214f..7ff6efa 100644
--- a/kernel_loader/src/lib.rs
+++ b/kernel_loader/src/lib.rs
@@ -6,6 +6,7 @@ use std::ffi::CStr;
 use std::fmt::{self, Display};
 use std::io::{Read, Seek, SeekFrom};
 use std::mem;
+use std::os::unix::io::AsRawFd;
 
 use sys_util::{GuestAddress, GuestMemory};
 
@@ -73,7 +74,7 @@ pub fn load_kernel<F>(
     kernel_image: &mut F,
 ) -> Result<u64>
 where
-    F: Read + Seek,
+    F: Read + Seek + AsRawFd,
 {
     let mut ehdr: elf::Elf64_Ehdr = Default::default();
     kernel_image
@@ -171,8 +172,9 @@ pub fn load_cmdline(
 #[cfg(test)]
 mod test {
     use super::*;
-    use std::io::Cursor;
-    use sys_util::{GuestAddress, GuestMemory};
+    use std::fs::File;
+    use std::io::Write;
+    use sys_util::{GuestAddress, GuestMemory, SharedMemory};
 
     const MEM_SIZE: u64 = 0x8000;
 
@@ -223,21 +225,29 @@ mod test {
     }
 
     // Elf64 image that prints hello world on x86_64.
-    fn make_elf_bin() -> Vec<u8> {
-        let mut v = Vec::new();
-        v.extend_from_slice(include_bytes!("test_elf.bin"));
-        v
+    fn make_elf_bin() -> File {
+        let elf_bytes = include_bytes!("test_elf.bin");
+        let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
+        shm.set_size(elf_bytes.len() as u64)
+            .expect("failed to set shared memory size");
+        shm.write_all(elf_bytes)
+            .expect("failed to write elf to shared memoy");
+        shm.into()
+    }
+
+    fn mutate_elf_bin(mut f: &File, offset: u64, val: u8) {
+        f.seek(SeekFrom::Start(offset))
+            .expect("failed to seek file");
+        f.write(&[val])
+            .expect("failed to write mutated value to file");
     }
 
     #[test]
     fn load_elf() {
         let gm = create_guest_mem();
         let kernel_addr = GuestAddress(0x0);
-        let image = make_elf_bin();
-        assert_eq!(
-            Ok(16613),
-            load_kernel(&gm, kernel_addr, &mut Cursor::new(&image))
-        );
+        let mut image = make_elf_bin();
+        assert_eq!(Ok(16613), load_kernel(&gm, kernel_addr, &mut image));
     }
 
     #[test]
@@ -245,10 +255,10 @@ mod test {
         let gm = create_guest_mem();
         let kernel_addr = GuestAddress(0x0);
         let mut bad_image = make_elf_bin();
-        bad_image[0x1] = 0x33;
+        mutate_elf_bin(&bad_image, 0x1, 0x33);
         assert_eq!(
             Err(Error::InvalidElfMagicNumber),
-            load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))
+            load_kernel(&gm, kernel_addr, &mut bad_image)
         );
     }
 
@@ -258,10 +268,10 @@ mod test {
         let gm = create_guest_mem();
         let kernel_addr = GuestAddress(0x0);
         let mut bad_image = make_elf_bin();
-        bad_image[0x5] = 2;
+        mutate_elf_bin(&bad_image, 0x5, 2);
         assert_eq!(
             Err(Error::BigEndianElfOnLittle),
-            load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))
+            load_kernel(&gm, kernel_addr, &mut bad_image)
         );
     }
 
@@ -271,10 +281,10 @@ mod test {
         let gm = create_guest_mem();
         let kernel_addr = GuestAddress(0x0);
         let mut bad_image = make_elf_bin();
-        bad_image[0x20] = 0x10;
+        mutate_elf_bin(&bad_image, 0x20, 0x10);
         assert_eq!(
             Err(Error::InvalidProgramHeaderOffset),
-            load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))
+            load_kernel(&gm, kernel_addr, &mut bad_image)
         );
     }
 }
diff --git a/qcow/Cargo.toml b/qcow/Cargo.toml
index 06bf9f5..0c521fd 100644
--- a/qcow/Cargo.toml
+++ b/qcow/Cargo.toml
@@ -12,3 +12,4 @@ byteorder = "*"
 libc = "*"
 remain = "*"
 sys_util = { path = "../sys_util" }
+data_model = { path = "../data_model" }
\ No newline at end of file
diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs
index d7759eb..acd76b7 100644
--- a/qcow/src/qcow.rs
+++ b/qcow/src/qcow.rs
@@ -7,9 +7,12 @@ mod refcount;
 mod vec_cache;
 
 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use data_model::{VolatileMemory, VolatileSlice};
 use libc::{EINVAL, ENOSPC, ENOTSUP};
 use remain::sorted;
-use sys_util::{error, FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroes};
+use sys_util::{
+    error, FileReadWriteVolatile, FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroes,
+};
 
 use std::cmp::min;
 use std::fmt::{self, Display};
@@ -1303,6 +1306,64 @@ impl QcowFile {
         }
         Ok(())
     }
+
+    // Reads `count` bytes from the cursor position, calling `cb` repeatedly with the backing file,
+    // number of bytes read so far, and number of bytes to read from the file in that invocation. If
+    // None is given to `cb` in place of the backing file, the `cb` should infer zeros would have
+    // been read.
+    fn read_cb<F>(&mut self, count: usize, mut cb: F) -> std::io::Result<usize>
+    where
+        F: FnMut(Option<&mut File>, usize, usize) -> std::io::Result<()>,
+    {
+        let address: u64 = self.current_offset as u64;
+        let read_count: usize = self.limit_range_file(address, count);
+
+        let mut nread: usize = 0;
+        while nread < read_count {
+            let curr_addr = address + nread as u64;
+            let file_offset = self.file_offset_read(curr_addr)?;
+            let count = self.limit_range_cluster(curr_addr, read_count - nread);
+
+            if let Some(offset) = file_offset {
+                self.raw_file.file_mut().seek(SeekFrom::Start(offset))?;
+                cb(Some(self.raw_file.file_mut()), nread, count)?;
+            } else {
+                cb(None, nread, count)?;
+            }
+
+            nread += count;
+        }
+        self.current_offset += read_count as u64;
+        Ok(read_count)
+    }
+
+    // Writes `count` bytes to the cursor position, calling `cb` repeatedly with the backing file,
+    // number of bytes written so far, and number of bytes to write to the file in that invocation.
+    fn write_cb<F>(&mut self, count: usize, mut cb: F) -> std::io::Result<usize>
+    where
+        F: FnMut(&mut File, usize, usize) -> std::io::Result<()>,
+    {
+        let address: u64 = self.current_offset as u64;
+        let write_count: usize = self.limit_range_file(address, count);
+
+        let mut nwritten: usize = 0;
+        while nwritten < write_count {
+            let curr_addr = address + nwritten as u64;
+            let offset = self.file_offset_write(curr_addr)?;
+            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
+
+            if let Err(e) = self.raw_file.file_mut().seek(SeekFrom::Start(offset)) {
+                return Err(e);
+            }
+            if let Err(e) = cb(self.raw_file.file_mut(), nwritten, count) {
+                return Err(e);
+            }
+
+            nwritten += count;
+        }
+        self.current_offset += write_count as u64;
+        Ok(write_count)
+    }
 }
 
 impl Drop for QcowFile {
@@ -1319,31 +1380,15 @@ impl AsRawFd for QcowFile {
 
 impl Read for QcowFile {
     fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
-        let address: u64 = self.current_offset as u64;
-        let read_count: usize = self.limit_range_file(address, buf.len());
-
-        let mut nread: usize = 0;
-        while nread < read_count {
-            let curr_addr = address + nread as u64;
-            let file_offset = self.file_offset_read(curr_addr)?;
-            let count = self.limit_range_cluster(curr_addr, read_count - nread);
-
-            if let Some(offset) = file_offset {
-                self.raw_file.file_mut().seek(SeekFrom::Start(offset))?;
-                self.raw_file
-                    .file_mut()
-                    .read_exact(&mut buf[nread..(nread + count)])?;
-            } else {
-                // Previously unwritten region, return zeros
-                for b in &mut buf[nread..(nread + count)] {
+        self.read_cb(buf.len(), |file, offset, count| match file {
+            Some(f) => f.read_exact(&mut buf[offset..(offset + count)]),
+            None => {
+                for b in &mut buf[offset..(offset + count)] {
                     *b = 0;
                 }
+                Ok(())
             }
-
-            nread += count;
-        }
-        self.current_offset += read_count as u64;
-        Ok(read_count)
+        })
     }
 }
 
@@ -1381,30 +1426,9 @@ impl Seek for QcowFile {
 
 impl Write for QcowFile {
     fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
-        let address: u64 = self.current_offset as u64;
-        let write_count: usize = self.limit_range_file(address, buf.len());
-
-        let mut nwritten: usize = 0;
-        while nwritten < write_count {
-            let curr_addr = address + nwritten as u64;
-            let offset = self.file_offset_write(curr_addr)?;
-            let count = self.limit_range_cluster(curr_addr, write_count - nwritten);
-
-            if let Err(e) = self.raw_file.file_mut().seek(SeekFrom::Start(offset)) {
-                return Err(e);
-            }
-            if let Err(e) = self
-                .raw_file
-                .file_mut()
-                .write(&buf[nwritten..(nwritten + count)])
-            {
-                return Err(e);
-            }
-
-            nwritten += count;
-        }
-        self.current_offset += write_count as u64;
-        Ok(write_count)
+        self.write_cb(buf.len(), |file, offset, count| {
+            file.write_all(&buf[offset..(offset + count)])
+        })
     }
 
     fn flush(&mut self) -> std::io::Result<()> {
@@ -1414,6 +1438,28 @@ impl Write for QcowFile {
     }
 }
 
+impl FileReadWriteVolatile for QcowFile {
+    fn read_volatile(&mut self, slice: VolatileSlice) -> io::Result<usize> {
+        self.read_cb(slice.size() as usize, |file, offset, count| {
+            let sub_slice = slice.get_slice(offset as u64, count as u64).unwrap();
+            match file {
+                Some(f) => f.read_exact_volatile(sub_slice),
+                None => {
+                    sub_slice.write_bytes(0);
+                    Ok(())
+                }
+            }
+        })
+    }
+
+    fn write_volatile(&mut self, slice: VolatileSlice) -> io::Result<usize> {
+        self.write_cb(slice.size() as usize, |file, offset, count| {
+            let sub_slice = slice.get_slice(offset as u64, count as u64).unwrap();
+            file.write_all_volatile(sub_slice)
+        })
+    }
+}
+
 impl FileSync for QcowFile {
     fn fsync(&mut self) -> std::io::Result<()> {
         self.flush()
diff --git a/sys_util/src/file_traits.rs b/sys_util/src/file_traits.rs
index 2dfc28d..584ac9a 100644
--- a/sys_util/src/file_traits.rs
+++ b/sys_util/src/file_traits.rs
@@ -3,7 +3,12 @@
 // found in the LICENSE file.
 
 use std::fs::File;
-use std::io::Result;
+use std::io::{Error, ErrorKind, Result};
+use std::os::unix::io::AsRawFd;
+
+use data_model::VolatileSlice;
+
+use libc::{c_void, read, write};
 
 /// A trait for flushing the contents of a file to disk.
 /// This is equivalent to File's `sync_all` method, but
@@ -35,3 +40,80 @@ impl FileSetLen for File {
         File::set_len(self, len)
     }
 }
+
+/// A trait similar to `Read` and `Write`, but uses volatile memory as buffers.
+pub trait FileReadWriteVolatile {
+    /// Read bytes from this file into the given slice, returning the number of bytes read on
+    /// success.
+    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
+
+    /// Reads bytes from this into the given slice until all bytes in the slice are written, or an
+    /// error is returned.
+    fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
+        while slice.size() > 0 {
+            let bytes_read = self.read_volatile(slice)?;
+            if bytes_read == 0 {
+                return Err(Error::from(ErrorKind::UnexpectedEof));
+            }
+            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
+            // a panic.
+            slice = slice.offset(bytes_read as u64).unwrap();
+        }
+        Ok(())
+    }
+
+    /// Write bytes from the slice to the given file, returning the number of bytes written on
+    /// success.
+    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
+
+    /// Write bytes from the slice to the given file until all the bytes from the slice have been
+    /// written, or an error is returned.
+    fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
+        while slice.size() > 0 {
+            let bytes_written = self.write_volatile(slice)?;
+            if bytes_written == 0 {
+                return Err(Error::from(ErrorKind::WriteZero));
+            }
+            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
+            // a panic.
+            slice = slice.offset(bytes_written as u64).unwrap();
+        }
+        Ok(())
+    }
+}
+
+impl FileReadWriteVolatile for File {
+    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
+        // Safe because only bytes inside the slice are accessed and the kernel is expected to
+        // handle arbitrary memory for I/O.
+        let ret = unsafe {
+            read(
+                self.as_raw_fd(),
+                slice.as_ptr() as *mut c_void,
+                slice.size() as usize,
+            )
+        };
+        if ret >= 0 {
+            Ok(ret as usize)
+        } else {
+            Err(Error::last_os_error())
+        }
+    }
+
+    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
+        // Safe because only bytes inside the slice are accessed and the kernel is expected to
+        // handle arbitrary memory for I/O.
+        let ret = unsafe {
+            write(
+                self.as_raw_fd(),
+                slice.as_ptr() as *const c_void,
+                slice.size() as usize,
+            )
+        };
+        if ret >= 0 {
+            Ok(ret as usize)
+        } else {
+            Err(Error::last_os_error())
+        }
+    }
+}
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
index aad5b37..40ae925 100644
--- a/sys_util/src/guest_memory.rs
+++ b/sys_util/src/guest_memory.rs
@@ -6,7 +6,6 @@
 
 use std::ffi::CStr;
 use std::fmt::{self, Display};
-use std::io::{Read, Write};
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::result;
 use std::sync::Arc;
@@ -432,7 +431,7 @@ impl GuestMemory {
         })
     }
 
-    /// Reads data from a readable object like a File and writes it to guest memory.
+    /// Reads data from a file descriptor and writes it to guest memory.
     ///
     /// # Arguments
     /// * `guest_addr` - Begin writing memory at this offset.
@@ -458,15 +457,12 @@ impl GuestMemory {
     /// #     Ok(rand_val)
     /// # }
     /// ```
-    pub fn read_to_memory<F>(
+    pub fn read_to_memory(
         &self,
         guest_addr: GuestAddress,
-        src: &mut F,
+        src: &AsRawFd,
         count: usize,
-    ) -> Result<()>
-    where
-        F: Read,
-    {
+    ) -> Result<()> {
         self.do_in_region(guest_addr, move |mapping, offset| {
             mapping
                 .read_to_memory(offset, src, count)
@@ -474,7 +470,7 @@ impl GuestMemory {
         })
     }
 
-    /// Writes data from memory to a writable object.
+    /// Writes data from memory to a file descriptor.
     ///
     /// # Arguments
     /// * `guest_addr` - Begin reading memory from this offset.
@@ -498,15 +494,12 @@ impl GuestMemory {
     /// #     Ok(())
     /// # }
     /// ```
-    pub fn write_from_memory<F>(
+    pub fn write_from_memory(
         &self,
         guest_addr: GuestAddress,
-        dst: &mut F,
+        dst: &AsRawFd,
         count: usize,
-    ) -> Result<()>
-    where
-        F: Write,
-    {
+    ) -> Result<()> {
         self.do_in_region(guest_addr, move |mapping, offset| {
             mapping
                 .write_from_memory(offset, dst, count)
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs
index e2942af..9e2e623 100644
--- a/sys_util/src/lib.rs
+++ b/sys_util/src/lib.rs
@@ -65,7 +65,7 @@ pub use crate::terminal::*;
 pub use crate::timerfd::*;
 pub use poll_token_derive::*;
 
-pub use crate::file_traits::{FileSetLen, FileSync};
+pub use crate::file_traits::{FileReadWriteVolatile, FileSetLen, FileSync};
 pub use crate::guest_memory::Error as GuestMemoryError;
 pub use crate::mmap::Error as MmapError;
 pub use crate::seek_hole::SeekHole;
diff --git a/sys_util/src/mmap.rs b/sys_util/src/mmap.rs
index f5df598..9f573e4 100644
--- a/sys_util/src/mmap.rs
+++ b/sys_util/src/mmap.rs
@@ -5,17 +5,18 @@
 //! The mmap module provides a safe interface to mmap memory and ensures unmap is called when the
 //! mmap object leaves scope.
 
-use std;
+use std::cmp::min;
 use std::collections::BTreeMap;
 use std::fmt::{self, Display};
-use std::io::{Read, Write};
-use std::mem::ManuallyDrop;
+use std::io;
+use std::mem::{size_of, ManuallyDrop};
 use std::os::unix::io::AsRawFd;
-use std::ptr::null_mut;
+use std::ptr::{copy_nonoverlapping, null_mut, read_unaligned, write_unaligned};
+
+use libc::{self, c_int, c_void, read, write};
 
 use data_model::volatile_memory::*;
 use data_model::DataInit;
-use libc::{self, c_int};
 
 use crate::{errno, pagesize};
 
@@ -31,14 +32,12 @@ pub enum Error {
     Overlapping(usize, usize),
     /// Requested memory range spans past the end of the region.
     InvalidRange(usize, usize, usize),
-    /// Couldn't read from the given source.
-    ReadFromSource(std::io::Error),
     /// `mmap` returned the given error.
     SystemCallFailed(errno::Error),
     /// Writing to memory failed
-    WriteToMemory(std::io::Error),
+    ReadToMemory(io::Error),
     /// Reading from memory failed
-    ReadFromMemory(std::io::Error),
+    WriteFromMemory(io::Error),
 }
 pub type Result<T> = std::result::Result<T, Error>;
 
@@ -60,10 +59,9 @@ impl Display for Error {
                 "requested memory range spans past the end of the region: offset={} count={} region_size={}",
                 offset, count, region_size,
             ),
-            ReadFromSource(e) => write!(f, "failed to read from the given source: {}", e),
             SystemCallFailed(e) => write!(f, "mmap system call failed: {}", e),
-            WriteToMemory(e) => write!(f, "failed to write to memory: {}", e),
-            ReadFromMemory(e) => write!(f, "failed to read from memory: {}", e),
+            ReadToMemory(e) => write!(f, "failed to read from file to memory: {}", e),
+            WriteFromMemory(e) => write!(f, "failed to write from memory to file: {}", e),
         }
     }
 }
@@ -330,15 +328,18 @@ impl MemoryMapping {
     ///     assert_eq!(res.unwrap(), 5);
     /// ```
     pub fn write_slice(&self, buf: &[u8], offset: usize) -> Result<usize> {
-        if offset >= self.size {
-            return Err(Error::InvalidAddress);
-        }
-        unsafe {
-            // Guest memory can't strictly be modeled as a slice because it is
-            // volatile.  Writing to it with what compiles down to a memcpy
-            // won't hurt anything as long as we get the bounds checks right.
-            let mut slice: &mut [u8] = &mut self.as_mut_slice()[offset..];
-            Ok(slice.write(buf).map_err(Error::WriteToMemory)?)
+        match self.size.checked_sub(offset) {
+            Some(size_past_offset) => {
+                let bytes_copied = min(size_past_offset, buf.len());
+                // The bytes_copied equation above ensures we don't copy bytes out of range of
+                // either buf or this slice. We also know that the buffers do not overlap because
+                // slices can never occupy the same memory as a volatile slice.
+                unsafe {
+                    copy_nonoverlapping(buf.as_ptr(), self.as_ptr().add(offset), bytes_copied);
+                }
+                Ok(bytes_copied)
+            }
+            None => Err(Error::InvalidAddress),
         }
     }
 
@@ -358,16 +359,23 @@ impl MemoryMapping {
     ///     assert!(res.is_ok());
     ///     assert_eq!(res.unwrap(), 16);
     /// ```
-    pub fn read_slice(&self, mut buf: &mut [u8], offset: usize) -> Result<usize> {
-        if offset >= self.size {
-            return Err(Error::InvalidAddress);
-        }
-        unsafe {
-            // Guest memory can't strictly be modeled as a slice because it is
-            // volatile.  Writing to it with what compiles down to a memcpy
-            // won't hurt anything as long as we get the bounds checks right.
-            let slice: &[u8] = &self.as_slice()[offset..];
-            Ok(buf.write(slice).map_err(Error::ReadFromMemory)?)
+    pub fn read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize> {
+        match self.size.checked_sub(offset) {
+            Some(size_past_offset) => {
+                let bytes_copied = min(size_past_offset, buf.len());
+                // The bytes_copied equation above ensures we don't copy bytes out of range of
+                // either buf or this slice. We also know that the buffers do not overlap because
+                // slices can never occupy the same memory as a volatile slice.
+                unsafe {
+                    copy_nonoverlapping(
+                        self.as_ptr().add(offset) as *const u8,
+                        buf.as_mut_ptr(),
+                        bytes_copied,
+                    );
+                }
+                Ok(bytes_copied)
+            }
+            None => Err(Error::InvalidAddress),
         }
     }
 
@@ -384,14 +392,12 @@ impl MemoryMapping {
     ///     assert!(res.is_ok());
     /// ```
     pub fn write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()> {
+        self.range_end(offset, size_of::<T>())?;
+        // This is safe because we checked the bounds above.
         unsafe {
-            // Guest memory can't strictly be modeled as a slice because it is
-            // volatile.  Writing to it with what compiles down to a memcpy
-            // won't hurt anything as long as we get the bounds checks right.
-            self.range_end(offset, std::mem::size_of::<T>())?;
-            std::ptr::write_volatile(&mut self.as_mut_slice()[offset..] as *mut _ as *mut T, val);
-            Ok(())
+            write_unaligned(self.as_ptr().add(offset) as *mut T, val);
         }
+        Ok(())
     }
 
     /// Reads on object from the memory region at the given offset.
@@ -411,17 +417,17 @@ impl MemoryMapping {
     ///     assert_eq!(55, num);
     /// ```
     pub fn read_obj<T: DataInit>(&self, offset: usize) -> Result<T> {
-        self.range_end(offset, std::mem::size_of::<T>())?;
+        self.range_end(offset, size_of::<T>())?;
+        // This is safe because by definition Copy types can have their bits set arbitrarily and
+        // still be valid.
         unsafe {
-            // This is safe because by definition Copy types can have their bits
-            // set arbitrarily and still be valid.
-            Ok(std::ptr::read_volatile(
-                &self.as_slice()[offset..] as *const _ as *const T,
+            Ok(read_unaligned(
+                self.as_ptr().add(offset) as *const u8 as *const T
             ))
         }
     }
 
-    /// Reads data from a readable object like a File and writes it to guest memory.
+    /// Reads data from a file descriptor and writes it to guest memory.
     ///
     /// # Arguments
     /// * `mem_offset` - Begin writing memory at this offset.
@@ -444,24 +450,44 @@ impl MemoryMapping {
     /// #     Ok(rand_val)
     /// # }
     /// ```
-    pub fn read_to_memory<F>(&self, mem_offset: usize, src: &mut F, count: usize) -> Result<()>
-    where
-        F: Read,
-    {
-        let mem_end = self
-            .range_end(mem_offset, count)
+    pub fn read_to_memory(
+        &self,
+        mut mem_offset: usize,
+        src: &AsRawFd,
+        mut count: usize,
+    ) -> Result<()> {
+        self.range_end(mem_offset, count)
             .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
-        unsafe {
-            // It is safe to overwrite the volatile memory.  Acessing the guest
-            // memory as a mutable slice is OK because nothing assumes another
-            // thread won't change what is loaded.
-            let dst = &mut self.as_mut_slice()[mem_offset..mem_end];
-            src.read_exact(dst).map_err(Error::ReadFromSource)?;
+        while count > 0 {
+            // The check above ensures that no memory outside this slice will get accessed by this
+            // read call.
+            match unsafe {
+                read(
+                    src.as_raw_fd(),
+                    self.as_ptr().add(mem_offset) as *mut c_void,
+                    count,
+                )
+            } {
+                0 => {
+                    return Err(Error::ReadToMemory(io::Error::from(
+                        io::ErrorKind::UnexpectedEof,
+                    )))
+                }
+                r if r < 0 => return Err(Error::ReadToMemory(io::Error::last_os_error())),
+                ret => {
+                    let bytes_read = ret as usize;
+                    match count.checked_sub(bytes_read) {
+                        Some(count_remaining) => count = count_remaining,
+                        None => break,
+                    }
+                    mem_offset += ret as usize;
+                }
+            }
         }
         Ok(())
     }
 
-    /// Writes data from memory to a writable object.
+    /// Writes data from memory to a file descriptor.
     ///
     /// # Arguments
     /// * `mem_offset` - Begin reading memory from this offset.
@@ -483,19 +509,39 @@ impl MemoryMapping {
     /// #     Ok(())
     /// # }
     /// ```
-    pub fn write_from_memory<F>(&self, mem_offset: usize, dst: &mut F, count: usize) -> Result<()>
-    where
-        F: Write,
-    {
-        let mem_end = self
-            .range_end(mem_offset, count)
+    pub fn write_from_memory(
+        &self,
+        mut mem_offset: usize,
+        dst: &AsRawFd,
+        mut count: usize,
+    ) -> Result<()> {
+        self.range_end(mem_offset, count)
             .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
-        unsafe {
-            // It is safe to read from volatile memory.  Acessing the guest
-            // memory as a slice is OK because nothing assumes another thread
-            // won't change what is loaded.
-            let src = &self.as_mut_slice()[mem_offset..mem_end];
-            dst.write_all(src).map_err(Error::ReadFromSource)?;
+        while count > 0 {
+            // The check above ensures that no memory outside this slice will get accessed by this
+            // write call.
+            match unsafe {
+                write(
+                    dst.as_raw_fd(),
+                    self.as_ptr().add(mem_offset) as *const c_void,
+                    count,
+                )
+            } {
+                0 => {
+                    return Err(Error::WriteFromMemory(io::Error::from(
+                        io::ErrorKind::WriteZero,
+                    )))
+                }
+                ret if ret < 0 => return Err(Error::WriteFromMemory(io::Error::last_os_error())),
+                ret => {
+                    let bytes_written = ret as usize;
+                    match count.checked_sub(bytes_written) {
+                        Some(count_remaining) => count = count_remaining,
+                        None => break,
+                    }
+                    mem_offset += ret as usize;
+                }
+            }
         }
         Ok(())
     }
@@ -521,20 +567,6 @@ impl MemoryMapping {
         }
     }
 
-    unsafe fn as_slice(&self) -> &[u8] {
-        // This is safe because we mapped the area at addr ourselves, so this slice will not
-        // overflow. However, it is possible to alias.
-        std::slice::from_raw_parts(self.addr, self.size)
-    }
-
-    // TODO(dgreid) - refactor this so the mut from non-mut isn't necessary (bug: 938767)
-    #[allow(clippy::mut_from_ref)]
-    unsafe fn as_mut_slice(&self) -> &mut [u8] {
-        // This is safe because we mapped the area at addr ourselves, so this slice will not
-        // overflow. However, it is possible to alias.
-        std::slice::from_raw_parts_mut(self.addr, self.size)
-    }
-
     // Check that offset+count is valid and return the sum.
     fn range_end(&self, offset: usize, count: usize) -> Result<usize> {
         let mem_end = offset.checked_add(count).ok_or(Error::InvalidAddress)?;
diff --git a/sys_util/src/shm.rs b/sys_util/src/shm.rs
index a72fe70..bb008d9 100644
--- a/sys_util/src/shm.rs
+++ b/sys_util/src/shm.rs
@@ -4,7 +4,7 @@
 
 use std::ffi::CStr;
 use std::fs::File;
-use std::io::{Seek, SeekFrom};
+use std::io::{self, Read, Seek, SeekFrom, Write};
 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 
 use libc::{
@@ -178,12 +178,62 @@ impl SharedMemory {
     }
 }
 
+impl Read for SharedMemory {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.fd.read(buf)
+    }
+}
+
+impl Read for &SharedMemory {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (&self.fd).read(buf)
+    }
+}
+
+impl Write for SharedMemory {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.fd.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.fd.flush()
+    }
+}
+
+impl Write for &SharedMemory {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        (&self.fd).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        (&self.fd).flush()
+    }
+}
+
+impl Seek for SharedMemory {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.fd.seek(pos)
+    }
+}
+
+impl Seek for &SharedMemory {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        (&self.fd).seek(pos)
+    }
+}
+
 impl AsRawFd for SharedMemory {
     fn as_raw_fd(&self) -> RawFd {
         self.fd.as_raw_fd()
     }
 }
 
+impl AsRawFd for &SharedMemory {
+    fn as_raw_fd(&self) -> RawFd {
+        self.fd.as_raw_fd()
+    }
+}
+
 impl Into<File> for SharedMemory {
     fn into(self) -> File {
         self.fd
@@ -213,7 +263,6 @@ mod tests {
 
     use std::ffi::CString;
     use std::fs::read_link;
-    use std::io::repeat;
 
     use data_model::VolatileMemory;
 
@@ -312,8 +361,7 @@ mod tests {
         mmap1
             .get_slice(0, 4096)
             .expect("failed to get mmap slice")
-            .read_from(&mut repeat(0x45))
-            .expect("failed to fill mmap slice");
+            .write_bytes(0x45);
 
         for i in 0..4096 {
             assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
@@ -337,8 +385,7 @@ mod tests {
         mmap1
             .get_slice(0, 4096)
             .expect("failed to get mmap slice")
-            .read_from(&mut repeat(0x45))
-            .expect("failed to fill mmap slice");
+            .write_bytes(0x45);
 
         for i in 0..4096 {
             assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0);
diff --git a/x86_64/src/bzimage.rs b/x86_64/src/bzimage.rs
index 16a7338..d43d405 100644
--- a/x86_64/src/bzimage.rs
+++ b/x86_64/src/bzimage.rs
@@ -7,6 +7,7 @@
 
 use std::fmt::{self, Display};
 use std::io::{Read, Seek, SeekFrom};
+use std::os::unix::io::AsRawFd;
 
 use sys_util::{GuestAddress, GuestMemory};
 
@@ -57,7 +58,7 @@ pub fn load_bzimage<F>(
     kernel_image: &mut F,
 ) -> Result<(boot_params, u64)>
 where
-    F: Read + Seek,
+    F: Read + Seek + AsRawFd,
 {
     let mut params: boot_params = Default::default();
     kernel_image
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index 837dac4..3fe8d69 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -441,11 +441,11 @@ impl X8664arch {
     ///
     /// * `mem` - The memory to be used by the guest.
     /// * `kernel_image` - the File object for the specified kernel.
-    fn load_kernel(mem: &GuestMemory, mut kernel_image: &mut File) -> Result<(boot_params, u64)> {
+    fn load_kernel(mem: &GuestMemory, kernel_image: &mut File) -> Result<(boot_params, u64)> {
         let elf_result =
-            kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), &mut kernel_image);
+            kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), kernel_image);
         if elf_result == Err(kernel_loader::Error::InvalidElfMagicNumber) {
-            bzimage::load_bzimage(mem, GuestAddress(KERNEL_START_OFFSET), &mut kernel_image)
+            bzimage::load_bzimage(mem, GuestAddress(KERNEL_START_OFFSET), kernel_image)
                 .map_err(Error::LoadBzImage)
         } else {
             let kernel_end = elf_result.map_err(Error::LoadKernel)?;
diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs
index c2def2f..8b754bd 100644
--- a/x86_64/src/mptable.rs
+++ b/x86_64/src/mptable.rs
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 use std::fmt::{self, Display};
-use std::io;
 use std::mem;
 use std::result;
 use std::slice;
 
 use libc::c_char;
 
+use data_model::VolatileMemory;
 use devices::PciInterruptPin;
 use sys_util::{GuestAddress, GuestMemory};
 
@@ -135,8 +135,9 @@ pub fn setup_mptable(
         return Err(Error::AddressOverflow);
     }
 
-    mem.read_to_memory(base_mp, &mut io::repeat(0), mp_size)
-        .map_err(|_| Error::Clear)?;
+    mem.get_slice(base_mp.0, mp_size as u64)
+        .map_err(|_| Error::Clear)?
+        .write_bytes(0);
 
     {
         let size = mem::size_of::<mpf_intel>();
@@ -400,23 +401,14 @@ mod tests {
         let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
         let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap();
 
-        struct Sum(u8);
-        impl io::Write for Sum {
-            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-                for v in buf.iter() {
-                    self.0 = self.0.wrapping_add(*v);
-                }
-                Ok(buf.len())
-            }
-            fn flush(&mut self) -> io::Result<()> {
-                Ok(())
-            }
+        let mut buf = vec![0; mpc_table.length as usize];
+        mem.read_at_addr(&mut buf[..], mpc_offset).unwrap();
+        let mut sum: u8 = 0;
+        for &v in &buf {
+            sum = sum.wrapping_add(v);
         }
 
-        let mut sum = Sum(0);
-        mem.write_from_memory(mpc_offset, &mut sum, mpc_table.length as usize)
-            .unwrap();
-        assert_eq!(sum.0, 0);
+        assert_eq!(sum, 0);
     }
 
     #[test]