1use libc::{
5 SIGBUS, SIGHUP, SIGILL, SIGPIPE, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ, c_int, c_void, siginfo_t,
6};
7use log::error;
8
9use crate::FcExitCode;
10use crate::logger::{IncMetric, METRICS, StoreMetric};
11use crate::utils::signal::register_signal_handler;
12
13const SI_OFF_SYSCALL: isize = 6;
19
20const SYS_SECCOMP_CODE: i32 = 1;
21
22#[inline]
23fn exit_with_code(exit_code: FcExitCode) {
24 if let Err(err) = METRICS.write() {
26 error!("Failed to write metrics while stopping: {}", err);
27 }
28 unsafe { libc::_exit(exit_code as i32) };
30}
31
32macro_rules! generate_handler {
33 ($fn_name:ident ,$signal_name:ident, $exit_code:ident, $signal_metric:expr, $body:ident) => {
34 #[inline(always)]
35 extern "C" fn $fn_name(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
36 let si_signo = unsafe { (*info).si_signo };
38 let si_code = unsafe { (*info).si_code };
40
41 if num != si_signo || num != $signal_name {
42 exit_with_code(FcExitCode::UnexpectedError);
43 }
44 $signal_metric.store(1);
45
46 error!(
47 "Shutting down VM after intercepting signal {}, code {}.",
48 si_signo, si_code
49 );
50
51 $body(si_code, info);
52
53 match si_signo {
54 $signal_name => exit_with_code(crate::FcExitCode::$exit_code),
55 _ => exit_with_code(FcExitCode::UnexpectedError),
56 };
57 }
58 };
59}
60
61fn log_sigsys_err(si_code: c_int, info: *mut siginfo_t) {
62 if si_code != SYS_SECCOMP_CODE {
63 exit_with_code(FcExitCode::UnexpectedError);
65 }
66
67 let syscall = unsafe { *(info as *const i32).offset(SI_OFF_SYSCALL) };
70 error!(
71 "Shutting down VM after intercepting a bad syscall ({}).",
72 syscall
73 );
74}
75
76fn empty_fn(_si_code: c_int, _info: *mut siginfo_t) {}
77
78generate_handler!(
79 sigxfsz_handler,
80 SIGXFSZ,
81 SIGXFSZ,
82 METRICS.signals.sigxfsz,
83 empty_fn
84);
85
86generate_handler!(
87 sigxcpu_handler,
88 SIGXCPU,
89 SIGXCPU,
90 METRICS.signals.sigxcpu,
91 empty_fn
92);
93
94generate_handler!(
95 sigbus_handler,
96 SIGBUS,
97 SIGBUS,
98 METRICS.signals.sigbus,
99 empty_fn
100);
101
102generate_handler!(
103 sigsegv_handler,
104 SIGSEGV,
105 SIGSEGV,
106 METRICS.signals.sigsegv,
107 empty_fn
108);
109
110generate_handler!(
111 sigsys_handler,
112 SIGSYS,
113 BadSyscall,
114 METRICS.seccomp.num_faults,
115 log_sigsys_err
116);
117
118generate_handler!(
119 sighup_handler,
120 SIGHUP,
121 SIGHUP,
122 METRICS.signals.sighup,
123 empty_fn
124);
125generate_handler!(
126 sigill_handler,
127 SIGILL,
128 SIGILL,
129 METRICS.signals.sigill,
130 empty_fn
131);
132
133#[inline(always)]
134extern "C" fn sigpipe_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
135 let si_signo = unsafe { (*info).si_signo };
140 let si_code = unsafe { (*info).si_code };
142
143 if num != si_signo || num != SIGPIPE {
144 error!("Received invalid signal {}, code {}.", si_signo, si_code);
145 return;
146 }
147
148 METRICS.signals.sigpipe.inc();
149
150 error!("Received signal {}, code {}.", si_signo, si_code);
151}
152
153pub fn register_signal_handlers() -> vmm_sys_util::errno::Result<()> {
158 register_signal_handler(SIGSYS, sigsys_handler)?;
163 register_signal_handler(SIGBUS, sigbus_handler)?;
164 register_signal_handler(SIGSEGV, sigsegv_handler)?;
165 register_signal_handler(SIGXFSZ, sigxfsz_handler)?;
166 register_signal_handler(SIGXCPU, sigxcpu_handler)?;
167 register_signal_handler(SIGPIPE, sigpipe_handler)?;
168 register_signal_handler(SIGHUP, sighup_handler)?;
169 register_signal_handler(SIGILL, sigill_handler)?;
170 Ok(())
171}