1
Fork 0

unix: Unsafe-wrap stack_overflow::{drop,make}_handler

Note that current_guard is probably not unsafe for future work.
This commit is contained in:
Jubilee Young 2024-07-16 21:08:06 -07:00
parent fa628ceaff
commit c1740eee1e

View file

@ -206,6 +206,9 @@ mod imp {
libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size } libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size }
} }
/// # Safety
/// Mutates the alternate signal stack
#[forbid(unsafe_op_in_unsafe_fn)]
pub unsafe fn make_handler(main_thread: bool) -> Handler { pub unsafe fn make_handler(main_thread: bool) -> Handler {
if !NEED_ALTSTACK.load(Ordering::Relaxed) { if !NEED_ALTSTACK.load(Ordering::Relaxed) {
return Handler::null(); return Handler::null();
@ -213,27 +216,38 @@ mod imp {
if !main_thread { if !main_thread {
// Always write to GUARD to ensure the TLS variable is allocated. // Always write to GUARD to ensure the TLS variable is allocated.
let guard = current_guard().unwrap_or(0..0); let guard = unsafe { current_guard() }.unwrap_or(0..0);
GUARD.set((guard.start, guard.end)); GUARD.set((guard.start, guard.end));
} }
let mut stack = mem::zeroed(); // SAFETY: assuming stack_t is zero-initializable
sigaltstack(ptr::null(), &mut stack); let mut stack = unsafe { mem::zeroed() };
// SAFETY: reads current stack_t into stack
unsafe { sigaltstack(ptr::null(), &mut stack) };
// Configure alternate signal stack, if one is not already set. // Configure alternate signal stack, if one is not already set.
if stack.ss_flags & SS_DISABLE != 0 { if stack.ss_flags & SS_DISABLE != 0 {
stack = get_stack(); // SAFETY: We warned our caller this would happen!
sigaltstack(&stack, ptr::null_mut()); unsafe {
stack = get_stack();
sigaltstack(&stack, ptr::null_mut());
}
Handler { data: stack.ss_sp as *mut libc::c_void } Handler { data: stack.ss_sp as *mut libc::c_void }
} else { } else {
Handler::null() Handler::null()
} }
} }
/// # Safety
/// Must be called
/// - only with our handler or nullptr
/// - only when done with our altstack
/// This disables the alternate signal stack!
#[forbid(unsafe_op_in_unsafe_fn)]
pub unsafe fn drop_handler(data: *mut libc::c_void) { pub unsafe fn drop_handler(data: *mut libc::c_void) {
if !data.is_null() { if !data.is_null() {
let sigstack_size = sigstack_size(); let sigstack_size = sigstack_size();
let page_size = PAGE_SIZE.load(Ordering::Relaxed); let page_size = PAGE_SIZE.load(Ordering::Relaxed);
let stack = libc::stack_t { let disabling_stack = libc::stack_t {
ss_sp: ptr::null_mut(), ss_sp: ptr::null_mut(),
ss_flags: SS_DISABLE, ss_flags: SS_DISABLE,
// Workaround for bug in macOS implementation of sigaltstack // Workaround for bug in macOS implementation of sigaltstack
@ -242,10 +256,11 @@ mod imp {
// both ss_sp and ss_size should be ignored in this case. // both ss_sp and ss_size should be ignored in this case.
ss_size: sigstack_size, ss_size: sigstack_size,
}; };
sigaltstack(&stack, ptr::null_mut()); // SAFETY: we warned the caller this disables the alternate signal stack!
// We know from `get_stackp` that the alternate stack we installed is part of a mapping unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) };
// that started one page earlier, so walk back a page and unmap from there. // SAFETY: We know from `get_stackp` that the alternate stack we installed is part of
munmap(data.sub(page_size), sigstack_size + page_size); // a mapping that started one page earlier, so walk back a page and unmap from there.
unsafe { munmap(data.sub(page_size), sigstack_size + page_size) };
} }
} }
@ -446,6 +461,7 @@ mod imp {
} }
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))] #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]
// FIXME: I am probably not unsafe.
unsafe fn current_guard() -> Option<Range<usize>> { unsafe fn current_guard() -> Option<Range<usize>> {
let stackptr = get_stack_start()?; let stackptr = get_stack_start()?;
let stackaddr = stackptr.addr(); let stackaddr = stackptr.addr();
@ -460,6 +476,7 @@ mod imp {
target_os = "netbsd", target_os = "netbsd",
target_os = "l4re" target_os = "l4re"
))] ))]
// FIXME: I am probably not unsafe.
unsafe fn current_guard() -> Option<Range<usize>> { unsafe fn current_guard() -> Option<Range<usize>> {
let mut ret = None; let mut ret = None;
let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); let mut attr: libc::pthread_attr_t = crate::mem::zeroed();