diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs index d8a6ced45a798511bcf1d1f0e53166448e1c7c07..fce06454c1583eac1aac6f4f15fa0630c17bd302 100644 --- a/redox-rt/src/arch/i686.rs +++ b/redox-rt/src/arch/i686.rs @@ -272,3 +272,11 @@ pub unsafe fn manually_enter_trampoline() { sc_saved_eip = const offset_of!(Sigcontrol, saved_ip), ); } +/// Get current stack pointer, weak granularity guarantees. +pub fn current_sp() -> usize { + let sp: usize; + unsafe { + core::arch::asm!("mov {}, esp", out(reg) sp); + } + sp +} diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index 9462313dde9836066def2f7915420d2f318d1c3c..fc425eecf5a4fc27fcac4b95336a24eb71456d17 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -375,3 +375,12 @@ pub unsafe fn manually_enter_trampoline() { sc_saved_rip = const offset_of!(Sigcontrol, saved_ip), ); } + +/// Get current stack pointer, weak granularity guarantees. +pub fn current_sp() -> usize { + let sp: usize; + unsafe { + core::arch::asm!("mov {}, rsp", out(reg) sp); + } + sp +} diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index af56b33473836e56946fee4ce52d0c1d268acb26..313519cff9beb147133bb601c20737317a873029 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -2,7 +2,7 @@ use core::cell::{Cell, UnsafeCell}; use core::ffi::c_int; use core::sync::atomic::{AtomicUsize, Ordering}; -use syscall::{RawAction, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; +use syscall::{RawAction, ENOMEM, EPERM, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ}; use syscall::{Error, Result, SetSighandlerData, SigProcControl, Sigcontrol, SigcontrolFlags, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, data::AtomicU64}; use crate::{arch::*, Tcb}; @@ -213,6 +213,7 @@ pub struct Sigaction { pub mask: u64, pub flags: SigactionFlags, } + impl Sigaction { fn ip(&self) -> usize { unsafe { @@ -446,3 +447,53 @@ pub fn current_setsighandler_struct() -> SetSighandlerData { proc_control_addr: &PROC_CONTROL_STRUCT as *const SigProcControl as usize, } } + +#[derive(Clone, Copy, Default, PartialEq)] +pub enum Sigaltstack { + #[default] + Disabled, + + Enabled { onstack: bool, base: *mut (), size: usize }, +} +pub unsafe fn sigaltstack(new: Option<&Sigaltstack>, old_out: Option<&mut Sigaltstack>) -> Result<()> { + let _g = tmp_disable_signals(); + let tcb = &mut *Tcb::current().unwrap().os_specific.arch.get(); + + let old = if tcb.altstack_bottom == 0 && tcb.altstack_top == usize::MAX { + Sigaltstack::Disabled + } else { + Sigaltstack::Enabled { + base: tcb.altstack_bottom as *mut (), + size: tcb.altstack_top - tcb.altstack_bottom, + onstack: (tcb.altstack_bottom..tcb.altstack_top).contains(&crate::arch::current_sp()), + } + }; + + if matches!(old, Sigaltstack::Enabled { onstack: true, .. }) && new != Some(&old) { + return Err(Error::new(EPERM)); + } + + if let Some(old_out) = old_out { + *old_out = old; + } + if let Some(new) = new { + match *new { + Sigaltstack::Disabled => { + tcb.altstack_bottom = 0; + tcb.altstack_top = usize::MAX; + } + Sigaltstack::Enabled { onstack: true, .. } => return Err(Error::new(EINVAL)), + Sigaltstack::Enabled { base, size, onstack: false } => { + if size < MIN_SIGALTSTACK_SIZE { + return Err(Error::new(ENOMEM)); + } + + tcb.altstack_bottom = base as usize; + tcb.altstack_top = base as usize + size; + } + } + } + Ok(()) +} + +pub const MIN_SIGALTSTACK_SIZE: usize = 8192; diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs index c015f3f9cb4587cea91d2c9dda8c5565bacca522..3b15084c2301bb13ce55c8b0aec7d3d8dab31448 100644 --- a/src/header/signal/mod.rs +++ b/src/header/signal/mod.rs @@ -127,16 +127,9 @@ pub unsafe extern "C" fn sigaddset(set: *mut sigset_t, signo: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - if !ss.is_null() { - if (*ss).ss_flags != SS_DISABLE as c_int { - return errno::EINVAL; - } - if (*ss).ss_size < MINSIGSTKSZ { - return errno::ENOMEM; - } - } - - Sys::sigaltstack(ss, old_ss) + Sys::sigaltstack(ss.as_ref(), old_ss.as_mut()) + .map(|()| 0) + .or_minus_one_errno() } #[no_mangle] diff --git a/src/platform/linux/signal.rs b/src/platform/linux/signal.rs index 0fbc8493e9e4f010440999809a37b5f0d79e9c2c..8762af6a6decac7bab45523bfe82319c704ffc6b 100644 --- a/src/platform/linux/signal.rs +++ b/src/platform/linux/signal.rs @@ -65,8 +65,13 @@ impl PalSignal for Sys { .map(|_| ()) } - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - e(syscall!(SIGALTSTACK, ss, old_ss)) as c_int + unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno> { + e_raw(syscall!( + SIGALTSTACK, + ss.map_or_else(core::ptr::null, |x| x as *const _), + old_ss.map_or_else(core::ptr::null_mut, |x| x as *mut _) + )) + .map(|_| ()) } unsafe fn sigpending(set: *mut sigset_t) -> c_int { diff --git a/src/platform/pal/signal.rs b/src/platform/pal/signal.rs index d85c35d955a0ecc98582006100a5a253668979da..d478ec16c82d0fd5359375d441e15956d91c9013 100644 --- a/src/platform/pal/signal.rs +++ b/src/platform/pal/signal.rs @@ -25,7 +25,7 @@ pub trait PalSignal: Pal { oact: Option<&mut sigaction>, ) -> Result<(), Errno>; - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int; + unsafe fn sigaltstack(ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<(), Errno>; unsafe fn sigpending(set: *mut sigset_t) -> c_int; diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 7001c07d72fc764f0ccebfc5212c549141151cc9..cdcf54611048295ddee04dbb78c4033c1bd21601 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -148,10 +148,7 @@ pub unsafe extern "C" fn redox_dup2_v1( } #[no_mangle] pub unsafe extern "C" fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult { - Error::mux(posix_read( - fd, - slice::from_raw_parts_mut(dst_base, dst_len), - )) + Error::mux(posix_read(fd, slice::from_raw_parts_mut(dst_base, dst_len))) } #[no_mangle] pub unsafe extern "C" fn redox_write_v1( diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index de8d1ee2b31e86ce35b5a1aa1672ac60d7192fc7..b495c590fd9c08bd4d82fbbf82281636fe361b9a 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -1,5 +1,5 @@ use core::mem; -use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, SignalHandler}; +use redox_rt::signal::{Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler}; use syscall::{self, Result}; use super::{ @@ -11,7 +11,7 @@ use crate::{ errno::{EINVAL, ENOSYS}, signal::{ sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, - SIG_SETMASK, SIG_UNBLOCK, + SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK, }, sys_time::{itimerval, ITIMER_REAL}, time::timespec, @@ -176,8 +176,51 @@ impl PalSignal for Sys { Ok(()) } - unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int { - unimplemented!() + unsafe fn sigaltstack( + new_c: Option<&stack_t>, + old_c: Option<&mut stack_t>, + ) -> Result<(), Errno> { + let new = new_c + .map(|c_stack| { + let flags = usize::try_from(c_stack.ss_flags).map_err(|_| Errno(EINVAL))?; + if flags != flags & (SS_DISABLE | SS_ONSTACK) { + return Err(Errno(EINVAL)); + } + + Ok(if flags & SS_DISABLE == SS_DISABLE { + Sigaltstack::Disabled + } else { + Sigaltstack::Enabled { + onstack: false, + base: c_stack.ss_sp.cast(), + size: c_stack.ss_size, + } + }) + }) + .transpose()?; + + let mut old = old_c.as_ref().map(|_| Sigaltstack::default()); + redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut())?; + + if let (Some(old_c_stack), Some(old)) = (old_c, old) { + *old_c_stack = match old { + Sigaltstack::Disabled => stack_t { + ss_sp: core::ptr::null_mut(), + ss_size: 0, + ss_flags: SS_DISABLE.try_into().unwrap(), + }, + Sigaltstack::Enabled { + onstack, + base, + size, + } => stack_t { + ss_sp: base.cast(), + ss_size: size, + ss_flags: SS_ONSTACK.try_into().unwrap(), + }, + }; + } + Ok(()) } unsafe fn sigpending(set: *mut sigset_t) -> c_int { diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index f6751cb510c42e03e49b9ff0e8c2c272a4df7f12..cfc56dd485afb5b21c985751fdcc80c0aedf546e 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -139,8 +139,8 @@ pub(crate) unsafe fn create( let mut current_sigmask = 0_u64; #[cfg(target_os = "redox")] { - current_sigmask = redox_rt::signal::get_sigmask() - .expect("failed to obtain sigprocmask for caller"); + current_sigmask = + redox_rt::signal::get_sigmask().expect("failed to obtain sigprocmask for caller"); } // Create a locked mutex, unlocked by the thread after it has started.