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, + location: Cell>>, } unsafe impl Send for CurrentTaskPtr {} @@ -42,7 +43,9 @@ impl DerefMut for CurrentTaskGuard<'_> { impl<'a> Drop for CurrentTaskGuard<'a> { fn drop(&mut self) { - CUR_TASK_PTR.borrow().borrowed.set(false); + let current = CUR_TASK_PTR.borrow(); + current.borrowed.set(false); + current.location.set(None); } } @@ -51,15 +54,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/signals.rs b/usertest/src/signals.rs index db167b1..09dc8b6 100644 --- a/usertest/src/signals.rs +++ b/usertest/src/signals.rs @@ -157,3 +157,63 @@ fn test_interruptible_waitpid() { } register_test!(test_interruptible_waitpid); + +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 rust_stack_overflow() { + segfault_child(|| { + #[allow(unconditional_recursion)] + fn recurse(n: usize) -> usize { + let m = std::hint::black_box(n) + 1; + recurse(m) + } + recurse(0); + }); +} + +register_test!(rust_stack_overflow);