summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--kvm/src/lib.rs23
-rw-r--r--sys_util/src/guest_memory.rs21
2 files changed, 38 insertions, 6 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index 8d3c61f..0a8d5c1 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -16,7 +16,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use std::ptr::copy_nonoverlapping;
 
 use libc::sigset_t;
-use libc::{open, EINVAL, ENOENT, ENOSPC, O_CLOEXEC, O_RDWR};
+use libc::{open, EINVAL, ENOENT, ENOSPC, EOVERFLOW, O_CLOEXEC, O_RDWR};
 
 use kvm_sys::*;
 
@@ -424,7 +424,9 @@ impl Vm {
         read_only: bool,
         log_dirty_pages: bool,
     ) -> Result<u32> {
-        if guest_addr < self.guest_mem.end_addr() {
+        let size = mem.size() as u64;
+        let end_addr = guest_addr.checked_add(size).ok_or(Error::new(EOVERFLOW))?;
+        if self.guest_mem.range_overlap(guest_addr, end_addr) {
             return Err(Error::new(ENOSPC));
         }
 
@@ -437,7 +439,7 @@ impl Vm {
                 read_only,
                 log_dirty_pages,
                 guest_addr.offset() as u64,
-                mem.size() as u64,
+                size,
                 mem.as_ptr(),
             )?
         };
@@ -483,7 +485,9 @@ impl Vm {
         read_only: bool,
         log_dirty_pages: bool,
     ) -> Result<u32> {
-        if guest_addr < self.guest_mem.end_addr() {
+        let size = mmap_arena.size() as u64;
+        let end_addr = guest_addr.checked_add(size).ok_or(Error::new(EOVERFLOW))?;
+        if self.guest_mem.range_overlap(guest_addr, end_addr) {
             return Err(Error::new(ENOSPC));
         }
 
@@ -496,7 +500,7 @@ impl Vm {
                 read_only,
                 log_dirty_pages,
                 guest_addr.offset() as u64,
-                mmap_arena.size() as u64,
+                size,
                 mmap_arena.as_ptr(),
             )?
         };
@@ -1923,12 +1927,19 @@ mod tests {
     #[test]
     fn add_memory() {
         let kvm = Kvm::new().unwrap();
-        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x1000)]).unwrap();
+        let gm = GuestMemory::new(&vec![
+            (GuestAddress(0), 0x1000),
+            (GuestAddress(0x5000), 0x5000),
+        ])
+        .unwrap();
         let mut vm = Vm::new(&kvm, gm).unwrap();
         let mem_size = 0x1000;
         let mem = MemoryMapping::new(mem_size).unwrap();
         vm.add_mmio_memory(GuestAddress(0x1000), mem, false, false)
             .unwrap();
+        let mem = MemoryMapping::new(mem_size).unwrap();
+        vm.add_mmio_memory(GuestAddress(0x10000), mem, false, false)
+            .unwrap();
     }
 
     #[test]
diff --git a/sys_util/src/guest_memory.rs b/sys_util/src/guest_memory.rs
index d40b5be..162960f 100644
--- a/sys_util/src/guest_memory.rs
+++ b/sys_util/src/guest_memory.rs
@@ -229,6 +229,14 @@ impl GuestMemory {
             .any(|region| region.guest_base <= addr && addr < region_end(region))
     }
 
+    /// Returns true if the given range (start, end) is overlap with the memory range
+    /// available to the guest.
+    pub fn range_overlap(&self, start: GuestAddress, end: GuestAddress) -> bool {
+        self.regions
+            .iter()
+            .any(|region| region.guest_base < end && start < region_end(region))
+    }
+
     /// Returns the address plus the offset if it is in range.
     pub fn checked_offset(&self, addr: GuestAddress, offset: u64) -> Option<GuestAddress> {
         addr.checked_add(offset).and_then(|a| {
@@ -614,6 +622,19 @@ mod tests {
         assert_eq!(gm.address_in_range(GuestAddress(0x3000)), false);
         assert_eq!(gm.address_in_range(GuestAddress(0x5000)), true);
         assert_eq!(gm.address_in_range(GuestAddress(0x6000)), false);
+        assert_eq!(gm.address_in_range(GuestAddress(0x6000)), false);
+        assert_eq!(
+            gm.range_overlap(GuestAddress(0x1000), GuestAddress(0x3000)),
+            true
+        );
+        assert_eq!(
+            gm.range_overlap(GuestAddress(0x3000), GuestAddress(0x4000)),
+            false
+        );
+        assert_eq!(
+            gm.range_overlap(GuestAddress(0x3000), GuestAddress(0x7000)),
+            true
+        );
         assert!(gm.checked_offset(GuestAddress(0x1000), 0x1000).is_none());
         assert!(gm.checked_offset(GuestAddress(0x5000), 0x800).is_some());
         assert!(gm.checked_offset(GuestAddress(0x5000), 0x1000).is_none());