mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
Implement a guard page for the kernel stack
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
c776954dfc
commit
5cc9f250dd
@ -1,7 +1,9 @@
|
|||||||
|
use crate::arch::mm::PageTableFlags;
|
||||||
use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE};
|
use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE};
|
||||||
use crate::cpu::CpuSet;
|
use crate::cpu::CpuSet;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::user::UserSpace;
|
use crate::user::UserSpace;
|
||||||
|
use crate::vm::page_table::KERNEL_PAGE_TABLE;
|
||||||
use crate::vm::{VmAllocOptions, VmSegment};
|
use crate::vm::{VmAllocOptions, VmSegment};
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ extern "C" {
|
|||||||
|
|
||||||
pub struct KernelStack {
|
pub struct KernelStack {
|
||||||
segment: VmSegment,
|
segment: VmSegment,
|
||||||
|
old_guard_page_flag: Option<PageTableFlags>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KernelStack {
|
impl KernelStack {
|
||||||
@ -47,12 +50,49 @@ impl KernelStack {
|
|||||||
segment: VmAllocOptions::new(KERNEL_STACK_SIZE / PAGE_SIZE)
|
segment: VmAllocOptions::new(KERNEL_STACK_SIZE / PAGE_SIZE)
|
||||||
.is_contiguous(true)
|
.is_contiguous(true)
|
||||||
.alloc_contiguous()?,
|
.alloc_contiguous()?,
|
||||||
|
old_guard_page_flag: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a kernel stack with a guard page.
|
||||||
|
/// An additional page is allocated and be regarded as a guard page, which should not be accessed.
|
||||||
|
pub fn new_with_guard_page() -> Result<Self> {
|
||||||
|
let stack_segment = VmAllocOptions::new(KERNEL_STACK_SIZE / PAGE_SIZE + 1)
|
||||||
|
.is_contiguous(true)
|
||||||
|
.alloc_contiguous()?;
|
||||||
|
let unpresent_flag = PageTableFlags::empty();
|
||||||
|
let old_guard_page_flag = Self::protect_guard_page(&stack_segment, unpresent_flag);
|
||||||
|
Ok(Self {
|
||||||
|
segment: stack_segment,
|
||||||
|
old_guard_page_flag: Some(old_guard_page_flag),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_paddr(&self) -> Paddr {
|
pub fn end_paddr(&self) -> Paddr {
|
||||||
self.segment.end_paddr()
|
self.segment.end_paddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_guard_page(&self) -> bool {
|
||||||
|
self.old_guard_page_flag.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn protect_guard_page(stack_segment: &VmSegment, flags: PageTableFlags) -> PageTableFlags {
|
||||||
|
let mut kernel_pt = KERNEL_PAGE_TABLE.get().unwrap().lock();
|
||||||
|
let guard_page_vaddr = {
|
||||||
|
let guard_page_paddr = stack_segment.start_paddr();
|
||||||
|
crate::vm::paddr_to_vaddr(guard_page_paddr)
|
||||||
|
};
|
||||||
|
// Safety: The protected address must be the address of guard page hence it should be safe and valid.
|
||||||
|
unsafe { kernel_pt.protect(guard_page_vaddr, flags).unwrap() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for KernelStack {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.has_guard_page() {
|
||||||
|
Self::protect_guard_page(&self.segment, self.old_guard_page_flag.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A task that executes a function to the end.
|
/// A task that executes a function to the end.
|
||||||
@ -225,7 +265,7 @@ impl TaskOptions {
|
|||||||
ctx: TaskContext::default(),
|
ctx: TaskContext::default(),
|
||||||
}),
|
}),
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
kstack: KernelStack::new()?,
|
kstack: KernelStack::new_with_guard_page()?,
|
||||||
link: LinkedListAtomicLink::new(),
|
link: LinkedListAtomicLink::new(),
|
||||||
priority: self.priority,
|
priority: self.priority,
|
||||||
cpu_affinity: self.cpu_affinity,
|
cpu_affinity: self.cpu_affinity,
|
||||||
@ -262,7 +302,7 @@ impl TaskOptions {
|
|||||||
ctx: TaskContext::default(),
|
ctx: TaskContext::default(),
|
||||||
}),
|
}),
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
kstack: KernelStack::new()?,
|
kstack: KernelStack::new_with_guard_page()?,
|
||||||
link: LinkedListAtomicLink::new(),
|
link: LinkedListAtomicLink::new(),
|
||||||
priority: self.priority,
|
priority: self.priority,
|
||||||
cpu_affinity: self.cpu_affinity,
|
cpu_affinity: self.cpu_affinity,
|
||||||
|
@ -156,7 +156,7 @@ impl<T: PageTableEntryTrait> PageTable<T, UserMode> {
|
|||||||
unsafe { self.do_unmap(vaddr) }
|
unsafe { self.do_unmap(vaddr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
pub fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<T::F, PageTableError> {
|
||||||
if is_kernel_vaddr(vaddr) {
|
if is_kernel_vaddr(vaddr) {
|
||||||
return Err(PageTableError::InvalidVaddr);
|
return Err(PageTableError::InvalidVaddr);
|
||||||
}
|
}
|
||||||
@ -201,12 +201,13 @@ impl<T: PageTableEntryTrait> PageTable<T, KernelMode> {
|
|||||||
|
|
||||||
/// Modify the flags mapped at `vaddr`. The `vaddr` should not be at the low address
|
/// Modify the flags mapped at `vaddr`. The `vaddr` should not be at the low address
|
||||||
/// (memory belonging to the user mode program).
|
/// (memory belonging to the user mode program).
|
||||||
|
/// If the modification succeeds, it will return the old flags of `vaddr`.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Modifying kernel mappings is considered unsafe, and incorrect operation may cause crashes.
|
/// Modifying kernel mappings is considered unsafe, and incorrect operation may cause crashes.
|
||||||
/// User must take care of the consequences when using this API.
|
/// User must take care of the consequences when using this API.
|
||||||
pub unsafe fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
pub unsafe fn protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<T::F, PageTableError> {
|
||||||
if is_user_vaddr(vaddr) {
|
if is_user_vaddr(vaddr) {
|
||||||
return Err(PageTableError::InvalidVaddr);
|
return Err(PageTableError::InvalidVaddr);
|
||||||
}
|
}
|
||||||
@ -319,22 +320,28 @@ impl<T: PageTableEntryTrait, M> PageTable<T, M> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify the flags mapped at `vaddr`
|
/// Modify the flags mapped at `vaddr`.
|
||||||
|
/// If the modification succeeds, it will return the old flags of `vaddr`.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function allows arbitrary modifications to the page table.
|
/// This function allows arbitrary modifications to the page table.
|
||||||
/// Incorrect modifications may cause the kernel to crash
|
/// Incorrect modifications may cause the kernel to crash
|
||||||
/// (e.g., make the linear mapping visible to the user mode applications.).
|
/// (e.g., make the linear mapping visible to the user mode applications.).
|
||||||
unsafe fn do_protect(&mut self, vaddr: Vaddr, flags: T::F) -> Result<(), PageTableError> {
|
unsafe fn do_protect(&mut self, vaddr: Vaddr, new_flags: T::F) -> Result<T::F, PageTableError> {
|
||||||
let last_entry = self.page_walk(vaddr, false).unwrap();
|
let last_entry = self.page_walk(vaddr, false).unwrap();
|
||||||
trace!("Page Table: Protect vaddr:{:x?}, flags:{:x?}", vaddr, flags);
|
let old_flags = last_entry.flags();
|
||||||
if last_entry.is_unused() || !last_entry.flags().is_present() {
|
trace!(
|
||||||
|
"Page Table: Protect vaddr:{:x?}, flags:{:x?}",
|
||||||
|
vaddr,
|
||||||
|
new_flags
|
||||||
|
);
|
||||||
|
if last_entry.is_unused() || !old_flags.is_present() {
|
||||||
return Err(PageTableError::InvalidModification);
|
return Err(PageTableError::InvalidModification);
|
||||||
}
|
}
|
||||||
last_entry.update(last_entry.paddr(), flags);
|
last_entry.update(last_entry.paddr(), new_flags);
|
||||||
tlb_flush(vaddr);
|
tlb_flush(vaddr);
|
||||||
Ok(())
|
Ok(old_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_paddr(&self) -> Paddr {
|
pub fn root_paddr(&self) -> Paddr {
|
||||||
|
Reference in New Issue
Block a user