From 60cdea81d988a458ef2a503cfad3a727ee1b4fdc Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 30 Apr 2019 16:28:46 +0800 Subject: [PATCH] fix check user ptr across VMAs --- crate/memory/src/memory_set/mod.rs | 54 ++++++++++++++++++++---------- kernel/src/process/structs.rs | 6 ++-- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index cf20ed0..9eb566a 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -3,6 +3,7 @@ use alloc::{boxed::Box, string::String, vec::Vec}; use core::fmt::{Debug, Error, Formatter}; +use core::mem::size_of; use crate::paging::*; @@ -52,16 +53,27 @@ impl MemoryArea { pub fn contains(&self, addr: VirtAddr) -> bool { addr >= self.start_addr && addr < self.end_addr } - /// Check the array is within the readable memory - fn check_read_array(&self, ptr: *const S, count: usize) -> bool { + /// Check the array is within the readable memory. + /// Return the size of space covered in the area. + fn check_read_array(&self, ptr: *const S, count: usize) -> usize { // page align - ptr as usize >= Page::of_addr(self.start_addr).start_address() - && unsafe { ptr.add(count) as usize } - < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address() + let min_bound = (ptr as usize).max(Page::of_addr(self.start_addr).start_address()); + let max_bound = unsafe { ptr.add(count) as usize } + .min(Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address()); + if max_bound >= min_bound { + max_bound - min_bound + } else { + 0 + } } - /// Check the array is within the writable memory - fn check_write_array(&self, ptr: *mut S, count: usize) -> bool { - !self.attr.readonly && self.check_read_array(ptr, count) + /// Check the array is within the writable memory. + /// Return the size of space covered in the area. + fn check_write_array(&self, ptr: *mut S, count: usize) -> usize { + if self.attr.readonly { + 0 + } else { + self.check_read_array(ptr, count) + } } /// Check the null-end C string is within the readable memory, and is valid. /// If so, clone it to a String. @@ -198,11 +210,14 @@ impl MemorySet { ptr: *const S, count: usize, ) -> VMResult<&'static [S]> { - self.areas - .iter() - .find(|area| area.check_read_array(ptr, count)) - .map(|_| core::slice::from_raw_parts(ptr, count)) - .ok_or(VMError::InvalidPtr) + let mut valid_size = 0; + for area in self.areas.iter() { + valid_size += area.check_read_array(ptr, count); + if valid_size == size_of::() * count { + return Ok(core::slice::from_raw_parts(ptr, count)); + } + } + Err(VMError::InvalidPtr) } /// Check the array is within the writable memory pub unsafe fn check_write_array( @@ -210,11 +225,14 @@ impl MemorySet { ptr: *mut S, count: usize, ) -> VMResult<&'static mut [S]> { - self.areas - .iter() - .find(|area| area.check_write_array(ptr, count)) - .map(|_| core::slice::from_raw_parts_mut(ptr, count)) - .ok_or(VMError::InvalidPtr) + let mut valid_size = 0; + for area in self.areas.iter() { + valid_size += area.check_write_array(ptr, count); + if valid_size == size_of::() * count { + return Ok(core::slice::from_raw_parts_mut(ptr, count)); + } + } + Err(VMError::InvalidPtr) } /// Check the null-end C string pointer array /// Used for getting argv & envp diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index 251203c..f9f07be 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -189,14 +189,14 @@ impl Thread { let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE; vm.push( ustack_buttom, - ustack_top - PAGE_SIZE, + ustack_top - PAGE_SIZE * 4, MemoryAttr::default().user(), Delay::new(GlobalFrameAlloc), "user_stack_delay", ); - // We are going to write init info now. So map the last page eagerly. + // We are going to write init info now. So map the last 4 pages eagerly. vm.push( - ustack_top - PAGE_SIZE, + ustack_top - PAGE_SIZE * 4, ustack_top, MemoryAttr::default().user(), ByFrame::new(GlobalFrameAlloc),