relibc: P5-signal-handler-panic-hardening — apply Phase 0e patch

Re-apply P5-signal-handler-panic-hardening.patch from local/patches/relibc/ to the local fork.
Multi-threading plan Phase 0e.
This commit is contained in:
2026-07-02 07:13:05 +03:00
parent 11569da01e
commit 1232fb742a
+64 -6
View File
@@ -1,4 +1,10 @@
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
use core::{
ffi::c_int,
hint::unreachable_unchecked,
panic::AssertUnwindSafe,
ptr::NonNull,
sync::atomic::Ordering,
};
use syscall::{
CallFlags, EAGAIN, EINTR, EINVAL, ENOMEM, EPERM, Error, RawAction, Result, SenderInfo,
@@ -103,6 +109,47 @@ pub struct SiginfoAbi {
pub si_value: usize, // sigval
}
fn invoke_signal_handler<F: FnOnce()>(f: AssertUnwindSafe<F>) -> bool {
fn do_call<F: FnOnce()>(data: *mut u8) {
let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
if let Some(callback) = callback.take() {
callback.0();
}
}
fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
let mut callback = Some(f);
unsafe {
core::intrinsics::catch_unwind(
do_call::<F>,
(&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
do_catch::<F>,
) != 0
}
}
#[inline(always)]
unsafe fn return_ignored_signal(
os: &RtTcb,
stack: &SigStack,
signals_were_disabled: bool,
) {
unsafe {
(*os.arch.get()).last_sig_was_restart = true;
(*os.arch.get()).last_sigstack = NonNull::new(stack.link);
}
if !signals_were_disabled {
core::sync::atomic::compiler_fence(Ordering::Release);
let control_flags = &os.control.control_flags;
control_flags.store(
control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(),
Ordering::Relaxed,
);
}
}
#[inline(always)]
unsafe fn inner(stack: &mut SigStack) {
let os = unsafe { &Tcb::current().unwrap().os_specific };
@@ -168,7 +215,10 @@ unsafe fn inner(stack: &mut SigStack) {
// and reaching this code. If so, we do already know whether the signal is IGNORED *now*,
// and so we should return early ideally without even temporarily touching the signal mask.
SigactionKind::Ignore => {
panic!("ctl {:#x?} signal {}", os.control, stack.sig_num)
unsafe {
return_ignored_signal(os, stack, signals_were_disabled);
}
return;
}
// this case should be treated equally as the one above
//
@@ -183,7 +233,9 @@ unsafe fn inner(stack: &mut SigStack) {
CallFlags::empty(),
&[ProcCall::Exit as u64, u64::from(sig) << 8],
);
panic!()
// SAFETY: ProcCall::Exit terminates the current process when it succeeds, so reaching
// this point would violate the proc manager exit contract.
unsafe { unreachable_unchecked() }
}
SigactionKind::Handled { handler } => handler,
};
@@ -224,15 +276,21 @@ unsafe fn inner(stack: &mut SigStack) {
si_uid: sender_uid as i32,
si_value: stack.sival,
};
unsafe {
if invoke_signal_handler(AssertUnwindSafe(|| unsafe {
sigaction(
stack.sig_num as c_int,
core::ptr::addr_of!(info).cast(),
stack as *mut SigStack as *mut (),
)
};
})) {
let _ = syscall::write(2, b"redox-rt: sa_siginfo handler panicked; continuing\n");
}
} else if let Some(handler) = unsafe { handler.handler } {
handler(stack.sig_num as c_int);
if invoke_signal_handler(AssertUnwindSafe(|| {
handler(stack.sig_num as c_int);
})) {
let _ = syscall::write(2, b"redox-rt: sa_handler panicked; continuing\n");
}
}
// Disable signals while we modify the sigmask again