1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
//! Installs signal handlers to catch critical program faults and logs them.
use libc::siginfo_t;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
use std::{
ffi::{c_int, c_void},
sync::Once,
};
static INIT_ONCE: Once = Once::new();
const FAULT_SIGNALS: [Signal; 5] = [
// Access to invalid memory address
Signal::SIGBUS,
// Floating point exception
Signal::SIGFPE,
// Illegal instructors
Signal::SIGILL,
// Invalid memory reference
Signal::SIGSEGV,
// Bad syscall
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 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_ptr: *mut c_void,
) {
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);
}
|