summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mullvad-daemon/src/exception_logging/unix.rs86
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);
}