From 7f04eee9625a22b3b41c222d43923ea66fff7673 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Mon, 12 Aug 2024 14:51:37 +0700 Subject: [PATCH] Fixes incorrect kernel mapping (#926) --- src/core/src/vmm/hw/ram/builder.rs | 52 ++++----------------------- src/core/src/vmm/hw/ram/mod.rs | 9 ----- src/core/src/vmm/mod.rs | 57 +++++++++++++++++++----------- 3 files changed, 44 insertions(+), 74 deletions(-) diff --git a/src/core/src/vmm/hw/ram/builder.rs b/src/core/src/vmm/hw/ram/builder.rs index 22767b2de..293d7ea7e 100644 --- a/src/core/src/vmm/hw/ram/builder.rs +++ b/src/core/src/vmm/hw/ram/builder.rs @@ -74,16 +74,15 @@ impl RamBuilder { /// # Panics /// If called a second time. - pub fn alloc_kernel(&mut self) -> KernelBuilder { - let start = self.next; - + pub fn alloc_kernel(&mut self, len: usize) -> Result<&mut [u8], RamError> { assert!(self.kern.is_none()); - KernelBuilder { - rb: self, - start, - len: 0, - } + let mem = unsafe { self.ram.alloc(self.next, len)? }; + + self.kern = Some(self.next..(self.next + len)); + self.next += len; + + Ok(mem) } /// # Panics @@ -383,43 +382,6 @@ impl RamBuilder { } } -/// Struct to allocate RAM to map the kernel. -pub struct KernelBuilder<'a> { - rb: &'a mut RamBuilder, - start: usize, - len: usize, -} - -impl<'a> KernelBuilder<'a> { - pub fn alloc_segment(&mut self, addr: usize, mut len: usize) -> Result<&mut [u8], RamError> { - // Check if addr valid. - if (addr % Ram::VM_PAGE_SIZE) != 0 { - return Err(RamError::UnalignedAddr); - } else if addr < self.len { - return Err(RamError::OverlappedAddr); - } - - len = len - .checked_next_multiple_of(Ram::VM_PAGE_SIZE) - .ok_or(RamError::InvalidLen)?; - - // Allocate. - let off = self.start.checked_add(addr).ok_or(RamError::InvalidAddr)?; - let seg = unsafe { self.rb.ram.alloc(off, len)? }; - - self.len = addr + len; - - Ok(seg) - } -} - -impl<'a> Drop for KernelBuilder<'a> { - fn drop(&mut self) { - self.rb.kern = Some(self.start..(self.start + self.len)); - self.rb.next += self.len; - } -} - /// Contains information how kernel arguments was allocated. pub struct KernelArgs { ram: Range, diff --git a/src/core/src/vmm/hw/ram/mod.rs b/src/core/src/vmm/hw/ram/mod.rs index 4efa5da89..0cf11cc96 100644 --- a/src/core/src/vmm/hw/ram/mod.rs +++ b/src/core/src/vmm/hw/ram/mod.rs @@ -160,18 +160,9 @@ unsafe impl Sync for Ram {} /// Represents an error when an operation on [`Ram`] fails. #[derive(Debug, Error)] pub enum RamError { - #[error("unaligned address")] - UnalignedAddr, - - #[error("overlapped address")] - OverlappedAddr, - #[error("invalid address")] InvalidAddr, - #[error("invalid length")] - InvalidLen, - #[error("host failed")] HostFailed(#[source] std::io::Error), } diff --git a/src/core/src/vmm/mod.rs b/src/core/src/vmm/mod.rs index baa1ca40a..ff8df60b5 100644 --- a/src/core/src/vmm/mod.rs +++ b/src/core/src/vmm/mod.rs @@ -124,7 +124,7 @@ pub unsafe extern "C" fn vmm_run( } // Parse program headers. - let mut loads = Vec::with_capacity(e_phnum); + let mut segments = Vec::with_capacity(e_phnum); let mut dynamic = None; for (index, data) in data.chunks_exact(e_phentsize).enumerate() { @@ -147,7 +147,7 @@ pub unsafe extern "C" fn vmm_run( return null_mut(); } - loads.push((p_offset, p_filesz, p_vaddr, p_memsz)); + segments.push((p_offset, p_filesz, p_vaddr, p_memsz)); } 2 => { if dynamic.is_some() { @@ -165,10 +165,10 @@ pub unsafe extern "C" fn vmm_run( } } - loads.sort_unstable_by_key(|i| i.2); + segments.sort_unstable_by_key(|i| i.2); // Make sure the first PT_LOAD includes the ELF header. - match loads.first() { + match segments.first() { Some(&(p_offset, _, _, _)) => { if p_offset != 0 { *err = RustError::new("the first PT_LOAD does not includes ELF header"); @@ -181,6 +181,29 @@ pub unsafe extern "C" fn vmm_run( } } + // Get kernel memory size. + let mut len = 0; + + for &(_, _, p_vaddr, p_memsz) in &segments { + if p_vaddr < len { + *err = RustError::new(format!( + "PT_LOAD at {p_vaddr:#x} is overlapped with the previous PT_LOAD" + )); + return null_mut(); + } + + len = match p_vaddr + .checked_add(p_memsz) + .and_then(|end| end.checked_next_multiple_of(Ram::VM_PAGE_SIZE)) + { + Some(v) => v, + None => { + *err = RustError::new(format!("invalid p_memsz on PT_LOAD at {p_vaddr:#x}")); + return null_mut(); + } + }; + } + // Setup RAM builder. let mut ram = match RamBuilder::new() { Ok(v) => v, @@ -191,21 +214,15 @@ pub unsafe extern "C" fn vmm_run( }; // Map the kernel. - let mut alloc = ram.alloc_kernel(); - - for &(p_offset, p_filesz, p_vaddr, p_memsz) in &loads { - // Allocate RAM for segment. - let seg = match alloc.alloc_segment(p_vaddr, p_memsz) { - Ok(v) => v, - Err(e) => { - *err = RustError::with_source( - format!("couldn't allocate RAM for a segment at {p_vaddr:#x}"), - e, - ); - return null_mut(); - } - }; + let kern = match ram.alloc_kernel(len) { + Ok(v) => v, + Err(e) => { + *err = RustError::with_source("couldn't allocate RAM for the kernel", e); + return null_mut(); + } + }; + for &(p_offset, p_filesz, p_vaddr, p_memsz) in &segments { // Seek to segment data. match file.seek(SeekFrom::Start(p_offset)) { Ok(v) => { @@ -221,14 +238,14 @@ pub unsafe extern "C" fn vmm_run( } // Read segment data. + let seg = &mut kern[p_vaddr..(p_vaddr + p_memsz)]; + if let Err(e) = file.read_exact(&mut seg[..p_filesz]) { *err = RustError::with_source(format!("couldn't read kernet at offset {p_offset}"), e); return null_mut(); } } - drop(alloc); - // Allocate stack. if let Err(e) = ram.alloc_stack(1024 * 1024 * 2) { *err = RustError::with_source("couldn't allocate RAM for stack", e);