diff options
author | Dylan Reid <dgreid@chromium.org> | 2017-05-15 17:37:47 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-05-25 22:51:14 -0700 |
commit | d4eaa4056f84b256ccd7684d9cf7e4363b9cf413 (patch) | |
tree | 728fbb294cf5b603fe232c7e284c00ffdd9904ed /kernel_loader | |
parent | 37285dc09d8fe5988fb98dc20bf00fdda38b0843 (diff) | |
download | crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar.gz crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar.bz2 crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar.lz crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar.xz crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.tar.zst crosvm-d4eaa4056f84b256ccd7684d9cf7e4363b9cf413.zip |
sys_util: Add guest_memory
Add a module for accessing guest memory. This module will replace all the slices that are used to access it currently as those slices aren't valid because the memory is volatile and a volatile slice doesn't exist in rust. Modify the existing users so they no longer depend on the deprecated slice access. Change-Id: Ic0e86dacf66f68bd88ed9cc197cb14e45ada891d Signed-off-by: Dylan Reid <dgreid@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/509919
Diffstat (limited to 'kernel_loader')
-rw-r--r-- | kernel_loader/src/lib.rs | 110 |
1 files changed, 60 insertions, 50 deletions
diff --git a/kernel_loader/src/lib.rs b/kernel_loader/src/lib.rs index 0d88fa5..89b6348 100644 --- a/kernel_loader/src/lib.rs +++ b/kernel_loader/src/lib.rs @@ -8,6 +8,8 @@ use std::mem; use std::ffi::CStr; use std::io::{Read, Seek, SeekFrom}; +use sys_util::{GuestAddress, GuestMemory}; + #[allow(dead_code)] #[allow(non_camel_case_types)] #[allow(non_snake_case)] @@ -17,11 +19,12 @@ mod elf; #[derive(Debug, PartialEq)] pub enum Error { BigEndianElfOnLittle, + CommandLineCopy, CommandLineOverflow, - ImagePastRamEnd, InvalidElfMagicNumber, InvalidProgramHeaderSize, InvalidProgramHeaderOffset, + InvalidProgramHeaderAddress, ReadElfHeader, ReadKernelImage, ReadProgramHeader, @@ -35,10 +38,10 @@ pub type Result<T> = std::result::Result<T, Error>; /// /// # Arguments /// -/// * `guest_mem` - A u8 slice that will be partially overwritten by the kernel. +/// * `guest_mem` - The guest memory region the kernel is written to. /// * `kernel_start` - The offset into `guest_mem` at which to load the kernel. /// * `kernel_image` - Input vmlinux image. -pub fn load_kernel<F>(guest_mem: &mut [u8], kernel_start: usize, kernel_image: &mut F) -> Result<()> +pub fn load_kernel<F>(guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F) -> Result<()> where F: Read + Seek { let mut ehdr: elf::Elf64_Ehdr = Default::default(); @@ -81,15 +84,12 @@ pub fn load_kernel<F>(guest_mem: &mut [u8], kernel_start: usize, kernel_image: & continue; } - let mem_offset = phdr.p_paddr as usize + kernel_start; - let mem_end = mem_offset + phdr.p_filesz as usize; - if mem_end > guest_mem.len() { - return Err(Error::ImagePastRamEnd); - } - let mut dst = &mut guest_mem[mem_offset..mem_end]; kernel_image.seek(SeekFrom::Start(phdr.p_offset)) .map_err(|_| Error::SeekKernelStart)?; - kernel_image.read_exact(dst) + + let mem_offset = kernel_start.checked_add(phdr.p_paddr as usize) + .ok_or(Error::InvalidProgramHeaderAddress)?; + guest_mem.read_to_memory(mem_offset, kernel_image, phdr.p_filesz as usize) .map_err(|_| Error::ReadKernelImage)?; } @@ -101,23 +101,23 @@ pub fn load_kernel<F>(guest_mem: &mut [u8], kernel_start: usize, kernel_image: & /// # Arguments /// /// * `guest_mem` - A u8 slice that will be partially overwritten by the command line. -/// * `kernel_start` - The offset into `guest_mem` at which to load the command line. +/// * `guest_addr` - The address in `guest_mem` at which to load the command line. /// * `cmdline` - The kernel command line. -pub fn load_cmdline(guest_mem: &mut [u8], offset: usize, cmdline: &CStr) -> Result<()> { +pub fn load_cmdline(guest_mem: &GuestMemory, guest_addr: GuestAddress, cmdline: &CStr) -> Result<()> { let len = cmdline.to_bytes().len(); if len <= 0 { return Ok(()); } - let end = offset + len + 1; // Extra for null termination. - if end > guest_mem.len() { - return Err(Error::CommandLineOverflow); - } - let cmdline_slice = &mut guest_mem[offset..end]; - for (i, s) in cmdline_slice.iter_mut().enumerate() { - *s = cmdline.to_bytes().get(i).map_or(0, |c| (*c as u8)); + let end = guest_addr.checked_add(len + 1) + .ok_or(Error::CommandLineOverflow)?; // Extra for null termination. + if end > guest_mem.end_addr() { + return Err(Error::CommandLineOverflow)?; } + guest_mem.write_slice_at_addr(cmdline.to_bytes_with_nul(), guest_addr) + .map_err(|_| Error::CommandLineCopy)?; + Ok(()) } @@ -125,28 +125,46 @@ pub fn load_cmdline(guest_mem: &mut [u8], offset: usize, cmdline: &CStr) -> Resu mod test { use std::io::Cursor; use super::*; + use sys_util::{GuestAddress, GuestMemory}; + + const MEM_SIZE: usize = 0x8000; + + fn create_guest_mem() -> GuestMemory { + GuestMemory::new(&vec![(GuestAddress(0x0), MEM_SIZE)]).unwrap() + } #[test] fn cmdline_overflow() { - let mut mem = vec![0; 50]; + let gm = create_guest_mem(); + let cmdline_address = GuestAddress(MEM_SIZE - 5); assert_eq!(Err(Error::CommandLineOverflow), - load_cmdline(mem.as_mut_slice(), - 45, + load_cmdline(&gm, + cmdline_address, CStr::from_bytes_with_nul(b"12345\0").unwrap())); } #[test] fn cmdline_write_end() { - let mut mem = vec![0; 50]; + let gm = create_guest_mem(); + let mut cmdline_address = GuestAddress(45); assert_eq!(Ok(()), - load_cmdline(mem.as_mut_slice(), - 45, + load_cmdline(&gm, + cmdline_address, CStr::from_bytes_with_nul(b"1234\0").unwrap())); - assert_eq!(mem[45], '1' as u8); - assert_eq!(mem[46], '2' as u8); - assert_eq!(mem[47], '3' as u8); - assert_eq!(mem[48], '4' as u8); - assert_eq!(mem[49], '\0' as u8); + let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap(); + assert_eq!(val, '1' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap(); + assert_eq!(val, '2' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap(); + assert_eq!(val, '3' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap(); + assert_eq!(val, '4' as u8); + cmdline_address = cmdline_address.unchecked_add(1); + let val: u8 = gm.read_obj_from_addr(cmdline_address).unwrap(); + assert_eq!(val, '\0' as u8); } // Elf64 image that prints hello world on x86_64. @@ -158,50 +176,42 @@ mod test { #[test] fn load_elf() { + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); let image = make_elf_bin(); - let mut mem = Vec::<u8>::with_capacity(0x8000); - unsafe { - mem.set_len(0x8000); - } assert_eq!(Ok(()), - load_kernel(mem.as_mut_slice(), 0x0, &mut Cursor::new(&image))); + load_kernel(&gm, kernel_addr, &mut Cursor::new(&image))); } #[test] fn bad_magic() { - let mut mem = Vec::<u8>::with_capacity(0x8000); - unsafe { - mem.set_len(0x8000); - } + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); let mut bad_image = make_elf_bin(); bad_image[0x1] = 0x33; assert_eq!(Err(Error::InvalidElfMagicNumber), - load_kernel(mem.as_mut_slice(), 0x0, &mut Cursor::new(&bad_image))); + load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))); } #[test] fn bad_endian() { // Only little endian is supported - let mut mem = Vec::<u8>::with_capacity(0x8000); - unsafe { - mem.set_len(0x8000); - } + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); let mut bad_image = make_elf_bin(); bad_image[0x5] = 2; assert_eq!(Err(Error::BigEndianElfOnLittle), - load_kernel(mem.as_mut_slice(), 0x0, &mut Cursor::new(&bad_image))); + load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))); } #[test] fn bad_phoff() { // program header has to be past the end of the elf header - let mut mem = Vec::<u8>::with_capacity(0x8000); - unsafe { - mem.set_len(0x8000); - } + let gm = create_guest_mem(); + let kernel_addr = GuestAddress(0x0); let mut bad_image = make_elf_bin(); bad_image[0x20] = 0x10; assert_eq!(Err(Error::InvalidProgramHeaderOffset), - load_kernel(mem.as_mut_slice(), 0x0, &mut Cursor::new(&bad_image))); + load_kernel(&gm, kernel_addr, &mut Cursor::new(&bad_image))); } } |