From 1b660b4c63e4427d4e2030d9a58f507ea307eca4 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 19 Feb 2020 10:12:46 -0800 Subject: [PATCH 1/3] Exit signal handler normally, fixing up the context's IP This is in contrast to calling `Context::set_from_signal` directly, which would skip over typical signal handling teardown some platforms might require. pthread_sigmask are removed here as they only served to reset signal masks that Linux would apply when entering the signal handler. Now that we return normally from the signal handler, on Linux signals are unmasked normally. --- .../src/context/mod.rs | 28 ++----------- .../src/instance/signals.rs | 21 +++++++--- .../src/region/mmap.rs | 9 +++- .../src/sysdeps/linux.rs | 38 +++++++++-------- .../src/sysdeps/macos.rs | 41 +++++++++++-------- .../lucet-runtime-tests/src/guest_fault.rs | 32 +++++++++------ 6 files changed, 93 insertions(+), 76 deletions(-) diff --git a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs index 859b1a20b..a6f3b13b3 100644 --- a/lucet-runtime/lucet-runtime-internals/src/context/mod.rs +++ b/lucet-runtime/lucet-runtime-internals/src/context/mod.rs @@ -6,7 +6,6 @@ mod tests; use crate::instance::Instance; use crate::val::{val_to_reg, val_to_stack, RegVal, UntypedRetVal, Val}; -use nix::sys::signal; use std::arch::x86_64::{__m128, _mm_setzero_ps}; use std::ptr::NonNull; use std::{mem, ptr}; @@ -123,7 +122,6 @@ pub struct Context { // TODO ACF 2019-10-23: make Instance into a generic parameter? backstop_callback: *const unsafe extern "C" fn(*mut Instance), callback_data: *mut Instance, - sigset: signal::SigSet, } impl Context { @@ -137,7 +135,6 @@ impl Context { parent_ctx: ptr::null_mut(), backstop_callback: Context::default_backstop_callback as *const _, callback_data: ptr::null_mut(), - sigset: signal::SigSet::empty(), } } @@ -468,23 +465,16 @@ impl Context { let (stack, stack_start) = stack_builder.into_inner(); - // RSP, RBP, and sigset still remain to be initialized. // Stack pointer: this points to the return address that will be used by `swap`, in place // of the original (eg, in the host) return address. The return address this points to is // the address of the first function to run on `swap`: `lucet_context_bootstrap`. child.gpr.rsp = &mut stack[stack.len() - stack_start] as *mut u64 as u64; + // Base pointer: `rbp` will be saved through all guest code, and preserved for when we + // reach the backstop. This allows us to prepare an argument for `lucet_context_backstop` + // even at the entrypoint of the guest. child.gpr.rbp = child as *const Context as u64; - // Read the mask to be restored if we ever need to jump out of a signal handler. If this - // isn't possible, die. - signal::pthread_sigmask( - signal::SigmaskHow::SIG_SETMASK, - None, - Some(&mut child.sigset), - ) - .expect("pthread_sigmask could not be retrieved"); - Ok(()) } @@ -629,16 +619,6 @@ impl Context { lucet_context_set(to as *const Context); } - /// Like `set`, but also manages the return from a signal handler. - /// - /// TODO: the return type of this function should really be `Result`, but using - /// `!` as a type like that is currently experimental. - #[inline] - pub unsafe fn set_from_signal(to: &Context) -> Result<(), nix::Error> { - signal::pthread_sigmask(signal::SigmaskHow::SIG_SETMASK, Some(&to.sigset), None)?; - Context::set(to) - } - /// Clear (zero) return values. pub fn clear_retvals(&mut self) { self.retvals_gp = [0; 2]; @@ -726,7 +706,7 @@ extern "C" { /// Performs the context switch; implemented in assembly. /// /// Never returns because the current context is discarded. - fn lucet_context_set(to: *const Context) -> !; + pub(crate) fn lucet_context_set(to: *const Context) -> !; /// Runs an entry callback after performing a context switch. Implemented in assembly. /// diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index b638db30d..03427c36d 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -1,5 +1,4 @@ use crate::alloc::validate_sigstack_size; -use crate::context::Context; use crate::error::Error; use crate::instance::{ siginfo_ext::SiginfoExt, FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE, @@ -333,11 +332,23 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext }); if switch_to_host { + // Switch to host by preparing the context to switch when we return from the signal andler. + // We must return from the signal handler for POSIX reasons, so instead prepare the context + // that the signal handler will resume the program as if a call were made. First, by + // pointing the instruction pointer at `lucet_context_set`, then by preparing the argument + // that `lucet_context_set` should read from `rdi` - the context to switch to. + // + // NOTE: it is absolutely critical that `lucet_context_set` does not use the guest stack! + // If it did, and the signal being handled were a segfault from reaching the guard page, + // there would be no stack available for the function we return to. By not using stack + // space, `lucet_context_set` is safe for use even in handling guard page faults. + // + // TODO: `rdi` is only correct for SysV (unixy) calling conventions! For Windows x86_64 this + // would be `rcx`, with other architectures being their own question. + ctx.set_ip(crate::context::lucet_context_set as *const c_void); HOST_CTX.with(|host_ctx| unsafe { - Context::set_from_signal(&*host_ctx.get()) - .expect("can successfully switch back to the host context"); - }); - unreachable!() + ctx.set_rdi(host_ctx.get() as u64); + }) } } diff --git a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs index dd5418480..24be83113 100644 --- a/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs +++ b/lucet-runtime/lucet-runtime-internals/src/region/mmap.rs @@ -376,10 +376,17 @@ impl MmapRegion { // lay out the other sections in memory let heap = mem as usize + instance_heap_offset(); - let stack = heap + region.limits.heap_address_space_size + host_page_size(); + let stack_guard = heap + region.limits.heap_address_space_size; + let stack = stack_guard + host_page_size(); let globals = stack + region.limits.stack_size; let sigstack = globals + region.limits.globals_size + host_page_size(); + // ensure we've accounted for all space + assert_eq!( + sigstack + region.limits.signal_stack_size - mem as usize, + region.limits.total_memory_size() + ); + Ok(Slot { start: mem, heap: heap as *mut c_void, diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs index fb576d8a1..da58e43cb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/linux.rs @@ -1,50 +1,56 @@ -use libc::{c_void, ucontext_t, REG_RIP}; +use libc::{c_void, ucontext_t, REG_RDI, REG_RIP}; #[derive(Clone, Copy, Debug)] -pub struct UContextPtr(*const ucontext_t); +pub struct UContextPtr(*mut ucontext_t); impl UContextPtr { #[inline] - pub fn new(ptr: *const c_void) -> Self { + pub fn new(ptr: *mut c_void) -> Self { assert!(!ptr.is_null(), "non-null context"); - UContextPtr(ptr as *const ucontext_t) + UContextPtr(ptr as *mut ucontext_t) } #[inline] pub fn get_ip(self) -> *const c_void { - let mcontext = &unsafe { *(self.0) }.uc_mcontext; + let mcontext = &unsafe { self.0.as_ref().unwrap() }.uc_mcontext; mcontext.gregs[REG_RIP as usize] as *const _ } + + #[inline] + pub fn set_ip(self, new_ip: *const c_void) { + let mut mcontext = &mut unsafe { self.0.as_mut().unwrap() }.uc_mcontext; + mcontext.gregs[REG_RIP as usize] = new_ip as i64; + } + + #[inline] + pub fn set_rdi(self, new_rdi: u64) { + let mut mcontext = &mut unsafe { self.0.as_mut().unwrap() }.uc_mcontext; + mcontext.gregs[REG_RDI as usize] = new_rdi as i64; + } } #[repr(C)] #[derive(Clone, Copy)] pub struct UContext { - context: ucontext_t, + context: *mut ucontext_t, } impl UContext { #[inline] - pub fn new(ptr: *const c_void) -> Self { + pub fn new(ptr: *mut c_void) -> Self { UContext { - context: *unsafe { - (ptr as *const ucontext_t) - .as_ref() - .expect("non-null context") - }, + context: unsafe { (ptr as *mut ucontext_t).as_mut().expect("non-null context") }, } } pub fn as_ptr(&mut self) -> UContextPtr { - UContextPtr::new(&self.context as *const _ as *const _) + UContextPtr::new(self.context as *mut _ as *mut _) } } impl Into for UContextPtr { #[inline] fn into(self) -> UContext { - UContext { - context: unsafe { *(self.0) }, - } + UContext { context: self.0 } } } diff --git a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs index 3ea2e1c86..ebcae4cdf 100644 --- a/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs +++ b/lucet-runtime/lucet-runtime-internals/src/sysdeps/macos.rs @@ -118,54 +118,59 @@ pub struct ucontext_t { pub uc_stack: sigaltstack, pub uc_link: *const ucontext_t, pub uc_mcsize: size_t, - pub uc_mcontext: *const mcontext64, + pub uc_mcontext: *mut mcontext64, } #[derive(Clone, Copy, Debug)] -pub struct UContextPtr(*const ucontext_t); +pub struct UContextPtr(*mut ucontext_t); impl UContextPtr { #[inline] - pub fn new(ptr: *const c_void) -> Self { + pub fn new(ptr: *mut c_void) -> Self { assert!(!ptr.is_null(), "non-null context"); - UContextPtr(ptr as *const ucontext_t) + UContextPtr(ptr as *mut ucontext_t) } #[inline] pub fn get_ip(self) -> *const c_void { - let mcontext = &unsafe { *(*self.0).uc_mcontext }; + let mcontext = unsafe { (*self.0).uc_mcontext.as_ref().unwrap() }; mcontext.ss.rip as *const _ } + + #[inline] + pub fn set_ip(self, new_ip: *const c_void) { + let mcontext: &mut mcontext64 = unsafe { &mut (*self.0).uc_mcontext.as_mut().unwrap() }; + mcontext.ss.rip = new_ip as u64; + } + + #[inline] + pub fn set_rdi(self, new_rdi: u64) { + let mcontext: &mut mcontext64 = unsafe { &mut (*self.0).uc_mcontext.as_mut().unwrap() }; + mcontext.ss.rdi = new_rdi; + } } #[derive(Clone, Copy)] #[repr(C)] pub struct UContext { - context: ucontext_t, - mcontext: mcontext64, + context: *mut ucontext_t, } impl UContext { #[inline] - pub fn new(ptr: *const c_void) -> Self { - let context = *unsafe { - (ptr as *const ucontext_t) - .as_ref() - .expect("non-null context") - }; - let mcontext = unsafe { *context.uc_mcontext }; - UContext { context, mcontext } + pub fn new(ptr: *mut c_void) -> Self { + let context = unsafe { (ptr as *mut ucontext_t).as_mut().expect("non-null context") }; + UContext { context } } pub fn as_ptr(&mut self) -> UContextPtr { - self.context.uc_mcontext = &self.mcontext; - UContextPtr::new(&self.context as *const _ as *const _) + UContextPtr::new(self.context as *mut _ as *mut _) } } impl Into for UContextPtr { #[inline] fn into(self) -> UContext { - UContext::new(self.0 as *const _) + UContext::new(self.0 as *mut _) } } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index f7b6f0693..114fb319c 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -141,7 +141,7 @@ pub fn mock_traps_module() -> Arc { macro_rules! guest_fault_tests { ( $TestRegion:path ) => { use lazy_static::lazy_static; - use libc::{c_void, pthread_kill, pthread_self, siginfo_t, SIGALRM, SIGSEGV}; + use libc::{c_void, pthread_kill, pthread_self, siginfo_t, SIGALRM, SIGBUS, SIGSEGV}; use lucet_runtime::vmctx::{lucet_vmctx, Vmctx}; use lucet_runtime::{ lucet_hostcall, lucet_hostcall_terminate, lucet_internal_ensure_linked, DlModule, @@ -441,8 +441,8 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, ) -> SignalBehavior { - // Triggered by a SIGSEGV writing to protected page - assert!(signum == SIGSEGV); + // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos + assert!(signum == SIGSEGV || signum == SIGBUS); // The fault was caused by writing to a protected page at `recoverable_ptr`. Make that // no longer be a fault @@ -488,8 +488,8 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, ) -> SignalBehavior { - // Triggered by a SIGSEGV writing to protected page - assert!(signum == SIGSEGV); + // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos + assert!(signum == SIGSEGV || signum == SIGBUS); // Terminate guest SignalBehavior::Terminate @@ -550,8 +550,8 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *mut siginfo_t, _ucontext_ptr: *mut c_void, ) { - // Triggered by a SIGSEGV writing to protected page - assert!(signum == SIGSEGV); + // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos + assert!(signum == SIGSEGV || signum == SIGBUS); unsafe { recoverable_ptr_make_accessible() }; *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; } @@ -571,6 +571,7 @@ macro_rules! guest_fault_tests { SigSet::all(), ); unsafe { sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds") }; + unsafe { sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds") }; match inst.run("illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { @@ -617,8 +618,8 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *mut siginfo_t, _ucontext_ptr: *mut c_void, ) { - // Triggered by a SIGSEGV writing to protected page - assert!(signum == SIGSEGV); + // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos + assert!(signum == SIGSEGV || signum == SIGBUS); unsafe { recoverable_ptr_make_accessible() }; *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; } @@ -638,8 +639,10 @@ macro_rules! guest_fault_tests { SigSet::empty(), ); - let saved_sa = + let saved_sigsegv_sa = unsafe { sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds") }; + let saved_sigbus_sa = + unsafe { sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds") }; // The original thread will run `sleepy_guest`, and the new thread will dereference a null // pointer after a delay. This should lead to a sigsegv while the guest is running, @@ -680,7 +683,12 @@ macro_rules! guest_fault_tests { unsafe { recoverable_ptr_teardown(); // sigaltstack(&saved_sigstack).expect("sigaltstack succeeds"); - sigaction(Signal::SIGSEGV, &saved_sa).expect("sigaction succeeds"); + sigaction(Signal::SIGSEGV, &saved_sigsegv_sa).expect("sigaction succeeds"); + } + unsafe { + recoverable_ptr_teardown(); + // sigaltstack(&saved_sigstack).expect("sigaltstack succeeds"); + sigaction(Signal::SIGBUS, &saved_sigbus_sa).expect("sigaction succeeds"); } drop(recoverable_ptr_lock); @@ -720,7 +728,7 @@ macro_rules! guest_fault_tests { ForkResult::Parent { child } => { match waitpid(Some(child), None).expect("can wait on child") { WaitStatus::Signaled(_, sig, _) => { - assert_eq!(sig, Signal::SIGSEGV); + assert!(sig == Signal::SIGSEGV || sig == Signal::SIGBUS); } ws => panic!("unexpected wait status: {:?}", ws), } From bdba52d159f302c50f59e5fc06a168737382e85f Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 27 Mar 2020 16:08:18 -0700 Subject: [PATCH 2/3] Fix tests on macos * conditionally define signals for invalid memory accesses per platform * add old macos module for version testing binary blob for the module is probably similar to the linux `old_module.so`, for which the source is not known. the macos `old_module.dylib` is built from `fibonacci.wat` as existed in Lucet commit `8639967` with the following command: ``` $ cargo run --bin lucetc ./lucetc/tests/wasm/fibonacci.wat ``` * make signal stacks sufficiently large in C API tests that mac CI passes --- .../src/instance/signals.rs | 2 +- .../lucet-runtime-tests/src/guest_fault.rs | 60 +++++++++--------- lucet-runtime/tests/c_api.c | 4 +- lucet-runtime/tests/version_checks.rs | 11 +++- .../tests/version_checks/old_module.dylib | Bin 0 -> 12936 bytes 5 files changed, 41 insertions(+), 36 deletions(-) create mode 100755 lucet-runtime/tests/version_checks/old_module.dylib diff --git a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs index 03427c36d..f417b00cb 100644 --- a/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs +++ b/lucet-runtime/lucet-runtime-internals/src/instance/signals.rs @@ -346,7 +346,7 @@ extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext // TODO: `rdi` is only correct for SysV (unixy) calling conventions! For Windows x86_64 this // would be `rcx`, with other architectures being their own question. ctx.set_ip(crate::context::lucet_context_set as *const c_void); - HOST_CTX.with(|host_ctx| unsafe { + HOST_CTX.with(|host_ctx| { ctx.set_rdi(host_ctx.get() as u64); }) } diff --git a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs index 114fb319c..dcab11e51 100644 --- a/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs +++ b/lucet-runtime/lucet-runtime-tests/src/guest_fault.rs @@ -166,6 +166,16 @@ macro_rules! guest_fault_tests { static mut RECOVERABLE_PTR: *mut libc::c_char = ptr::null_mut(); + #[cfg(target_os = "linux")] + const INVALID_PERMISSION_FAULT: libc::c_int = SIGSEGV; + #[cfg(not(target_os = "linux"))] + const INVALID_PERMISSION_FAULT: libc::c_int = SIGBUS; + + #[cfg(target_os = "linux")] + const INVALID_PERMISSION_SIGNAL: Signal = Signal::SIGSEGV; + #[cfg(not(target_os = "linux"))] + const INVALID_PERMISSION_SIGNAL: Signal = Signal::SIGBUS; + unsafe fn recoverable_ptr_setup() { assert!(RECOVERABLE_PTR.is_null()); RECOVERABLE_PTR = mmap( @@ -441,8 +451,7 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, ) -> SignalBehavior { - // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos - assert!(signum == SIGSEGV || signum == SIGBUS); + assert!(signum == INVALID_PERMISSION_FAULT); // The fault was caused by writing to a protected page at `recoverable_ptr`. Make that // no longer be a fault @@ -488,8 +497,7 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *const siginfo_t, _ucontext_ptr: *const c_void, ) -> SignalBehavior { - // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos - assert!(signum == SIGSEGV || signum == SIGBUS); + assert!(signum == INVALID_PERMISSION_FAULT); // Terminate guest SignalBehavior::Terminate @@ -542,7 +550,7 @@ macro_rules! guest_fault_tests { #[test] fn sigsegv_handler_saved_restored() { lazy_static! { - static ref HOST_SIGSEGV_TRIGGERED: Mutex = Mutex::new(false); + static ref HOST_FAULT_TRIGGERED: Mutex = Mutex::new(false); } extern "C" fn host_sigsegv_handler( @@ -550,10 +558,9 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *mut siginfo_t, _ucontext_ptr: *mut c_void, ) { - // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos - assert!(signum == SIGSEGV || signum == SIGBUS); + assert!(signum == INVALID_PERMISSION_FAULT); unsafe { recoverable_ptr_make_accessible() }; - *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; + *HOST_FAULT_TRIGGERED.lock().unwrap() = true; } test_ex(|| { // make sure only one test using RECOVERABLE_PTR is running at once @@ -570,8 +577,7 @@ macro_rules! guest_fault_tests { SaFlags::SA_RESTART, SigSet::all(), ); - unsafe { sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds") }; - unsafe { sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds") }; + unsafe { sigaction(INVALID_PERMISSION_SIGNAL, &sa).expect("sigaction succeeds") }; match inst.run("illegal_instr", &[]) { Err(Error::RuntimeFault(details)) => { @@ -584,20 +590,20 @@ macro_rules! guest_fault_tests { unsafe { recoverable_ptr_setup(); } - *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = false; + *HOST_FAULT_TRIGGERED.lock().unwrap() = false; // accessing this should trigger the segfault unsafe { *RECOVERABLE_PTR = 0; } - assert!(*HOST_SIGSEGV_TRIGGERED.lock().unwrap()); + assert!(*HOST_FAULT_TRIGGERED.lock().unwrap()); // clean up unsafe { recoverable_ptr_teardown(); sigaction( - Signal::SIGSEGV, + INVALID_PERMISSION_SIGNAL, &SigAction::new(SigHandler::SigDfl, SaFlags::SA_RESTART, SigSet::empty()), ) .expect("sigaction succeeds"); @@ -610,7 +616,7 @@ macro_rules! guest_fault_tests { #[test] fn sigsegv_handler_during_guest() { lazy_static! { - static ref HOST_SIGSEGV_TRIGGERED: Mutex = Mutex::new(false); + static ref HOST_FAULT_TRIGGERED: Mutex = Mutex::new(false); } extern "C" fn host_sigsegv_handler( @@ -618,10 +624,9 @@ macro_rules! guest_fault_tests { _siginfo_ptr: *mut siginfo_t, _ucontext_ptr: *mut c_void, ) { - // Triggered by a SIGSEGV writing to protected page, or SIGBUS on macos - assert!(signum == SIGSEGV || signum == SIGBUS); + assert!(signum == INVALID_PERMISSION_FAULT); unsafe { recoverable_ptr_make_accessible() }; - *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = true; + *HOST_FAULT_TRIGGERED.lock().unwrap() = true; } #[lucet_hostcall] @@ -639,10 +644,9 @@ macro_rules! guest_fault_tests { SigSet::empty(), ); - let saved_sigsegv_sa = - unsafe { sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds") }; - let saved_sigbus_sa = - unsafe { sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds") }; + let saved_fault_sa = unsafe { + sigaction(INVALID_PERMISSION_SIGNAL, &sa).expect("sigaction succeeds") + }; // The original thread will run `sleepy_guest`, and the new thread will dereference a null // pointer after a delay. This should lead to a sigsegv while the guest is running, @@ -668,14 +672,14 @@ macro_rules! guest_fault_tests { unsafe { recoverable_ptr_setup(); } - *HOST_SIGSEGV_TRIGGERED.lock().unwrap() = false; + *HOST_FAULT_TRIGGERED.lock().unwrap() = false; // accessing this should trigger the segfault unsafe { *RECOVERABLE_PTR = 0; } - assert!(*HOST_SIGSEGV_TRIGGERED.lock().unwrap()); + assert!(*HOST_FAULT_TRIGGERED.lock().unwrap()); child.join().expect("can join on child"); @@ -683,12 +687,8 @@ macro_rules! guest_fault_tests { unsafe { recoverable_ptr_teardown(); // sigaltstack(&saved_sigstack).expect("sigaltstack succeeds"); - sigaction(Signal::SIGSEGV, &saved_sigsegv_sa).expect("sigaction succeeds"); - } - unsafe { - recoverable_ptr_teardown(); - // sigaltstack(&saved_sigstack).expect("sigaltstack succeeds"); - sigaction(Signal::SIGBUS, &saved_sigbus_sa).expect("sigaction succeeds"); + sigaction(INVALID_PERMISSION_SIGNAL, &saved_fault_sa) + .expect("sigaction succeeds"); } drop(recoverable_ptr_lock); @@ -728,7 +728,7 @@ macro_rules! guest_fault_tests { ForkResult::Parent { child } => { match waitpid(Some(child), None).expect("can wait on child") { WaitStatus::Signaled(_, sig, _) => { - assert!(sig == Signal::SIGSEGV || sig == Signal::SIGBUS); + assert_eq!(sig, INVALID_PERMISSION_SIGNAL); } ws => panic!("unexpected wait status: {:?}", ws), } diff --git a/lucet-runtime/tests/c_api.c b/lucet-runtime/tests/c_api.c index b799d186f..a2665bab2 100644 --- a/lucet-runtime/tests/c_api.c +++ b/lucet-runtime/tests/c_api.c @@ -11,7 +11,7 @@ bool lucet_runtime_test_expand_heap(struct lucet_dl_module *mod) .heap_address_space_size = 8 * 1024 * 1024, .stack_size = 64 * 1024, .globals_size = 4096, - .signal_stack_size = 12 * 1024, + .signal_stack_size = 32 * 1024, }; enum lucet_error err; @@ -98,7 +98,7 @@ bool lucet_runtime_test_yield_resume(struct lucet_dl_module *mod) .heap_address_space_size = 8 * 1024 * 1024, .stack_size = 64 * 1024, .globals_size = 4096, - .signal_stack_size = 12 * 1024, + .signal_stack_size = 32 * 1024, }; enum lucet_error err; diff --git a/lucet-runtime/tests/version_checks.rs b/lucet-runtime/tests/version_checks.rs index fa5c9a30c..56bc1684a 100644 --- a/lucet-runtime/tests/version_checks.rs +++ b/lucet-runtime/tests/version_checks.rs @@ -2,9 +2,14 @@ use lucet_runtime::{DlModule, Error}; #[test] pub fn reject_old_modules() { - let err = DlModule::load("./tests/version_checks/old_module.so") - .err() - .unwrap(); + // for platforms where modules are ELF (BSD, Linux, ...), exclude macos as it uses a different + // file format (MachO) + #[cfg(all(unix, not(target_os = "macos")))] + const MODULE_PATH: &'static str = "./tests/version_checks/old_module.so"; + #[cfg(target_os = "macos")] + const MODULE_PATH: &'static str = "./tests/version_checks/old_module.dylib"; + + let err = DlModule::load(MODULE_PATH).err().unwrap(); if let Error::ModuleError(e) = err { let msg = format!("{}", e); diff --git a/lucet-runtime/tests/version_checks/old_module.dylib b/lucet-runtime/tests/version_checks/old_module.dylib new file mode 100755 index 0000000000000000000000000000000000000000..27743542cb6df83a7697f8bc193f3058b1d17b89 GIT binary patch literal 12936 zcmeI3Pe>GD6u`gH%q=Um0v+6O?vSGRr`y_*{2aS#tk4&ZeGP6QQ|z z=+H6f5_a(rp`8T16+{J55#gau+M&8gf%e|a``X#nJd~H{J$UoY`@Z+R@6B&c@9pgK z@1Ivng)oYR5L-dZK!=Nj7#9_AC&WI`yP!&SwsdvkOo6y=xk<7irYHe5XhkV2Hf-hG z3gdN`yKDEz1???4cQmqIGnZF$Q)iQBMd#zExdI#W!e`Cp6%AWq@`XXE_2YH#CLf50 z`+p~xR}fUGw$S<3mgbOV7N8wEAF^))YZS~&=Y;l7P(NrjsCPcxkjfy&S|PGd2)Lk6 zHH>&}p>)H17fj+Y=r;@Y4j8j1gz!ONeBT#9QSg1CBKK{e8$Bm1uPX;&7SCBIyE@r^ z|K!7LYt2mKmq*pdVXnfn<0#qFkdF`U>&V9ZSeO74U;<2l2`~XBzyz286JP@WB7u-S z7aU!}(kD0`J>mdlK z)qW|*mP_Q#YH7cc##1>qYe@Trv|mg6owUC#exN<0%PXsAgfxrF%cMOk?Y*VJv3Z}o zBColpI7c}b%@pfCly*=&3d>d;w}YZUz3IpV)#+ifby1gBtLwEt7NfC(@GCcp%kz<)--+o>?9n<4r# zu|Z4qW|9$=2*;DyQZT9rOn)X4v($}5#2Qw8W@<|(dJASiz!%hW#ORv+x{&ucR>ZLzZ3Vk$+Ayi>TtC@?TDSpe0QIh)0vook;2H{kd+)Ue3T(en1-%D7 z;ZmWuKpe;-Ivc&AyfyF3iH`I~)u5H>Q9bcwG-e9&^fV>(DP}mWoTJvJ=)OlQ=dq@< bK|$~}Tk%v9+A7I-FLXWhdF~S_{qKvP#JWfI literal 0 HcmV?d00001 From 78aa0ed52f67a10f03fa8b2821c3708622af1cae Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 27 Mar 2020 16:10:54 -0700 Subject: [PATCH 3/3] reenable mac CI also involves fixing some wasi-sdk installation bitrot --- .github/workflows/{mac-ci.yml.disabled => mac-ci.yml} | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) rename .github/workflows/{mac-ci.yml.disabled => mac-ci.yml} (69%) diff --git a/.github/workflows/mac-ci.yml.disabled b/.github/workflows/mac-ci.yml similarity index 69% rename from .github/workflows/mac-ci.yml.disabled rename to .github/workflows/mac-ci.yml index 29ccb688d..a9ebfc62d 100644 --- a/.github/workflows/mac-ci.yml.disabled +++ b/.github/workflows/mac-ci.yml @@ -18,9 +18,10 @@ jobs: - name: Install wasi-sdk (macos) run: | - curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-7/wasi-sdk-7.0-macos.tar.gz - tar xf wasi-sdk-7.0-macos.tar.gz - sudo mv wasi-sdk-7.0/opt /opt + curl -sS -L -O https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk-8.0-macos.tar.gz + tar xf wasi-sdk-8.0-macos.tar.gz + sudo mkdir -p /opt/wasi-sdk + sudo mv wasi-sdk-8.0/* /opt/wasi-sdk/ - name: Test Lucet run: make test-except-fuzz