From 8dfd003c727d34f77f030937594bf67c2850a909 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 18:03:14 -0600 Subject: [PATCH] Validate memory pointers --- kernel/scheme/user.rs | 118 +++++++++++++++++++----------------- kernel/syscall/validate.rs | 40 +++++++++--- schemes/example/src/main.rs | 1 + 3 files changed, 96 insertions(+), 63 deletions(-) diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index e5a0167..f2c797e 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -65,76 +65,84 @@ impl UserInner { } fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result { - let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); + if size == 0 { + Ok(0) + } else { + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); - let mut grants = context.grants.lock(); + let mut grants = context.grants.lock(); - let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); + let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; + let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); - let from_address = (address/4096) * 4096; - let offset = address - from_address; - let full_size = ((offset + size + 4095)/4096) * 4096; - let mut to_address = arch::USER_GRANT_OFFSET; + let from_address = (address/4096) * 4096; + let offset = address - from_address; + let full_size = ((offset + size + 4095)/4096) * 4096; + let mut to_address = arch::USER_GRANT_OFFSET; - let mut flags = entry::PRESENT | entry::NO_EXECUTE; - if writable { - flags |= entry::WRITABLE; - } - - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - if to_address + full_size < start { - grants.insert(i, Grant::new( - VirtualAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - flags, - &mut new_table, - &mut temporary_page - )); - - return Ok(to_address + offset); - } else { - let pages = (grants[i].size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; + let mut flags = entry::PRESENT | entry::NO_EXECUTE; + if writable { + flags |= entry::WRITABLE; } + + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + if to_address + full_size < start { + grants.insert(i, Grant::new( + VirtualAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + flags, + &mut new_table, + &mut temporary_page + )); + + return Ok(to_address + offset); + } else { + let pages = (grants[i].size() + 4095) / 4096; + let end = start + pages * 4096; + to_address = end; + } + } + + grants.push(Grant::new( + VirtualAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + flags, + &mut new_table, + &mut temporary_page + )); + + Ok(to_address + offset) } - - grants.push(Grant::new( - VirtualAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - flags, - &mut new_table, - &mut temporary_page - )); - - return Ok(to_address + offset); } pub fn release(&self, address: usize) -> Result<()> { - let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); + if address == 0 { + Ok(()) + } else { + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); - let mut grants = context.grants.lock(); + let mut grants = context.grants.lock(); - let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; - let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); + let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; + let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); - for i in 0 .. grants.len() { - let start = grants[i].start_address().get(); - let end = start + grants[i].size(); - if address >= start && address < end { - grants.remove(i).destroy(&mut new_table, &mut temporary_page); + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + let end = start + grants[i].size(); + if address >= start && address < end { + grants.remove(i).destroy(&mut new_table, &mut temporary_page); - return Ok(()); + return Ok(()); + } } - } - Err(Error::new(EFAULT)) + Err(Error::new(EFAULT)) + } } pub fn read(&self, buf: &mut [u8]) -> Result { diff --git a/kernel/syscall/validate.rs b/kernel/syscall/validate.rs index 2ba6ef7..361f58d 100644 --- a/kernel/syscall/validate.rs +++ b/kernel/syscall/validate.rs @@ -1,15 +1,39 @@ -use core::slice; +use core::{mem, slice}; +use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; use syscall::error::*; -/// Convert a pointer and length to slice, if valid -/// TODO: Check validity -pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T]> { - Ok(unsafe { slice::from_raw_parts(ptr, len) }) +fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> { + let active_table = unsafe { ActivePageTable::new() }; + + let start_page = Page::containing_address(VirtualAddress::new(address)); + let end_page = Page::containing_address(VirtualAddress::new(address + size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + let page_flags = active_table.translate_page_flags(page).ok_or(Error::new(EFAULT))?; + if ! page_flags.contains(flags) { + return Err(Error::new(EFAULT)); + } + } + + Ok(()) } /// Convert a pointer and length to slice, if valid -/// TODO: Check validity -pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) +pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T]> { + if len == 0 { + Ok(&[]) + } else { + validate(ptr as usize, len * mem::size_of::(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts(ptr, len) }) + } +} + +/// Convert a pointer and length to slice, if valid +pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { + if len == 0 { + Ok(&mut []) + } else { + validate(ptr as usize, len * mem::size_of::(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) + } } diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs index 9c7d3fe..84fb345 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -31,6 +31,7 @@ fn main(){ loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("example: failed to read events from example scheme"); + println!("{:?}", packet); scheme.handle(&mut packet); socket.write(&packet).expect("example: failed to write responses to example scheme"); }