diff options
| -rw-r--r-- | mullvad-daemon/src/exception_logging/unix.rs | 86 |
1 files changed, 67 insertions, 19 deletions
diff --git a/mullvad-daemon/src/exception_logging/unix.rs b/mullvad-daemon/src/exception_logging/unix.rs index 897ddeb780..977d3857b1 100644 --- a/mullvad-daemon/src/exception_logging/unix.rs +++ b/mullvad-daemon/src/exception_logging/unix.rs @@ -1,37 +1,85 @@ +//! Installs signal handlers to catch critical program faults and logs them. + use libc::{c_int, c_void, siginfo_t}; use nix::sys::signal::*; -/// Installs a signal handler. -pub fn enable() { - log::debug!("ENABLING EXCEPTION HANDLING"); +use std::{convert::TryFrom, sync::Once}; + +const INIT_ONCE: Once = Once::new(); - let mut signals = SigSet::empty(); +const FAULT_SIGNALS: [Signal; 5] = [ // Access to invalid memory address - signals.add(Signal::SIGBUS); + Signal::SIGBUS, // Floating point exception - signals.add(Signal::SIGFPE); + Signal::SIGFPE, // Illegal instructors - signals.add(Signal::SIGILL); + Signal::SIGILL, // Invalid memory reference - signals.add(Signal::SIGSEGV); + Signal::SIGSEGV, // Bad syscall - signals.add(Signal::SIGSYS); + Signal::SIGSYS, +]; +/// Installs a signal handler. +pub fn enable() { + INIT_ONCE.call_once(|| { + // Setup alt stack for signal handlers to be executed in. + // If the daemon ever needs to be compiled for architectures where memory can't be writeable + // and executable, the following block of code has to be disabled. This will also mean that + // stack overflows may be silent and undetectable in logs. + let sig_handler_flags = { + // The kernel will use the first properly aligned address, so alignment is not an issue. + let alt_stack = vec![0u8; libc::SIGSTKSZ]; + let stack_t = libc::stack_t { + ss_sp: alt_stack.as_ptr() as *mut c_void, + ss_flags: 0, + ss_size: alt_stack.len(), + }; + let ret = unsafe { libc::sigaltstack(&stack_t, std::ptr::null_mut()) }; + if ret != 0 { + log::error!( + "Failed to set alternative stack - {}", + std::io::Error::last_os_error() + ); + SaFlags::empty() + } else { + std::mem::forget(alt_stack); + SaFlags::SA_ONSTACK + } + }; - // let handler = ; - let signal_action = SigAction::new( - SigHandler::SigAction(fault_handler), - SaFlags::empty(), - signals, - ); + let signal_action = SigAction::new( + SigHandler::SigAction(fault_handler), + sig_handler_flags, + SigSet::empty(), + ); + + for signal in &FAULT_SIGNALS { + if let Err(err) = unsafe { sigaction(*signal, &signal_action) } { + log::error!("Failed to install signal handler for {}: {}", signal, err); + } + } + }); } /// Signal handler to catch signals that are used to indicate unrecoverable errors in the daemon extern "C" fn fault_handler( signum: c_int, - siginfo: *mut siginfo_t, - thread_context: *mut c_void, + _siginfo: *mut siginfo_t, + _thread_context_ptr: *mut c_void, ) { - log::error!("GOT SIGNAL - {}", signum); - panic!("FAILING WITH SIGNAL!"); + let signal: Signal = match Signal::try_from(signum) { + Ok(signal) => signal, + Err(err) => { + log::error!( + "Signal handler triggered by unknown signal {}, exiting: {}", + signum, + err + ); + std::process::exit(2); + } + }; + + log::error!("Caught signal {}", signal); + std::process::exit(2); } |
