diff --git a/scheme/user.rs b/scheme/user.rs index e5a016755d47bc75778af6c172a8079265fff92f..f2c797e4e83da3d471636a68dca4dbee9e11bfaa 100644 --- a/scheme/user.rs +++ b/scheme/user.rs @@ -65,76 +65,84 @@ impl UserInner { } fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> { - 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; - } + 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; + 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 - )); + 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); + 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<usize> { diff --git a/syscall/validate.rs b/syscall/validate.rs index 2ba6ef731f087d9d7a7f8b9799c26d54f9ff5311..361f58d94ff67af2a26da80ece4ec52a828b766b 100644 --- a/syscall/validate.rs +++ b/syscall/validate.rs @@ -1,15 +1,39 @@ -use core::slice; +use core::{mem, slice}; +use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; use syscall::error::*; +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<T>(ptr: *const T, len: usize) -> Result<&'static [T]> { - Ok(unsafe { slice::from_raw_parts(ptr, len) }) + if len == 0 { + Ok(&[]) + } else { + validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts(ptr, len) }) + } } /// Convert a pointer and length to slice, if valid -/// TODO: Check validity pub fn validate_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) + if len == 0 { + Ok(&mut []) + } else { + validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) + } }