diff --git a/src/arch/arm64/memory/fault.rs b/src/arch/arm64/memory/fault.rs index b462502..99628c7 100644 --- a/src/arch/arm64/memory/fault.rs +++ b/src/arch/arm64/memory/fault.rs @@ -10,6 +10,7 @@ use crate::{ memory::uaccess::UAccessResult, }, memory::fault::{FaultResolution, handle_demand_fault, handle_protection_fault}, + process::thread_group::signal::SigId, sched::{current::current_task, spawn_kernel_work}, }; use alloc::boxed::Box; @@ -119,15 +120,8 @@ pub fn handle_kernel_mem_fault(exception: Exception, info: AbortIss, state: &mut pub fn handle_mem_fault(exception: Exception, info: AbortIss) { match run_mem_fault_handler(exception, info) { Ok(FaultResolution::Resolved) => {} - // TODO: Implement proc signals. Ok(FaultResolution::Denied) => { - let task = current_task(); - panic!( - "SIGSEGV on process {} {:?} PC: {:x}", - task.process.tgid, - exception, - task.ctx.user().elr_el1 - ) + current_task().process.deliver_signal(SigId::SIGSEGV); } // If the page fault involves sleepy kernel work, we can // spawn that work on the process, since there is no other diff --git a/src/arch/arm64/proc/signal.rs b/src/arch/arm64/proc/signal.rs index dcc9a33..26f26d7 100644 --- a/src/arch/arm64/proc/signal.rs +++ b/src/arch/arm64/proc/signal.rs @@ -56,6 +56,9 @@ pub async fn do_signal(id: SigId, sa: UserspaceSigAction) -> Result, pub(super) borrowed: Cell, + pub location: Cell>>, } unsafe impl Send for CurrentTaskPtr {} @@ -51,15 +52,19 @@ impl CurrentTaskPtr { Self { ptr: Cell::new(ptr::null_mut()), borrowed: Cell::new(false), + location: Cell::new(None), } } + #[track_caller] pub fn current(&self) -> CurrentTaskGuard<'static> { if self.borrowed.get() { - panic!("Double mutable borrow of current task!"); + let other = self.location.take(); + panic!("Double mutable borrow of current task! Borrowed from: {other:?}"); } self.borrowed.set(true); + self.location.set(Some(*core::panic::Location::caller())); unsafe { let ptr = self.ptr.get(); diff --git a/usertest/src/main.rs b/usertest/src/main.rs index a13581b..4b97f1f 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -194,6 +194,53 @@ fn test_mincore() { register_test!(test_mincore); +fn segfault_child(inner: impl FnOnce()) { + unsafe { + let pid = libc::fork(); + if pid < 0 { + panic!("fork failed"); + } else if pid == 0 { + // Child process + inner() + } else { + // Parent process + let mut status = 0; + let rusage = std::ptr::null_mut(); + libc::wait4(pid, &mut status, 0, rusage); + + assert!(libc::WIFSIGNALED(status)); + assert_eq!(libc::WTERMSIG(status), libc::SIGSEGV); + } + } +} + +fn test_segfault_read() { + segfault_child(|| { + let addr: *const u8 = std::hint::black_box(std::ptr::null()); + let _ = unsafe { std::ptr::read(addr) }; + }); + segfault_child(|| { + // Ensure reading from kernel stack fails + let addr = 0xffff_ba00_0000_0000 as *const u8; + let _ = unsafe { std::ptr::read(addr) }; + }); +} + +register_test!(test_segfault_read); + +fn test_segfault_write() { + segfault_child(|| { + let addr: *mut u8 = std::hint::black_box(std::ptr::null_mut()); + unsafe { std::ptr::write(addr, 42) }; + }); + segfault_child(|| { + let addr = 0xffff_ba00_0000_0000 as *mut u8; + unsafe { std::ptr::write(addr, 42) }; + }); +} + +register_test!(test_segfault_write); + fn run_test(test_fn: fn()) -> Result<(), i32> { // Fork a new process to run the test unsafe {