diff options
-rw-r--r-- | kvm/src/lib.rs | 23 | ||||
-rw-r--r-- | sys_util/src/guest_memory.rs | 21 |
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()); |