segfault properly

This commit is contained in:
Troy Neubauer
2026-02-28 10:32:05 -08:00
parent 7ab93dc0c1
commit 704f4e05f0
4 changed files with 58 additions and 9 deletions

View File

@@ -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

View File

@@ -56,6 +56,9 @@ pub async fn do_signal(id: SigId, sa: UserspaceSigAction) -> Result<ExceptionSta
.align(PAGE_SIZE)
};
drop(signal);
drop(task);
copy_to_user(addr, frame).await?;
new_state.sp_el0 = addr.value() as _;

View File

@@ -17,6 +17,7 @@ per_cpu_private! {
pub(super) struct CurrentTaskPtr {
pub(super) ptr: Cell<*mut OwnedTask>,
pub(super) borrowed: Cell<bool>,
pub location: Cell<Option<core::panic::Location<'static>>>,
}
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();

View File

@@ -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 {