Skip to content

Commit f533bf1

Browse files
author
Alexandra Iordache
committed
vmm: handle SIGBUS & SIGSEGV
Log a message and exit with a specific exit code upon intercepting SIGBUS/SIGSEGV. Signed-off-by: Alexandra Iordache <[email protected]>
1 parent 65dc516 commit f533bf1

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

vmm/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ pub const FC_EXIT_CODE_GENERIC_ERROR: u8 = 1;
112112
pub const FC_EXIT_CODE_UNEXPECTED_ERROR: u8 = 2;
113113
/// Firecracker was shut down after intercepting a restricted system call.
114114
pub const FC_EXIT_CODE_BAD_SYSCALL: u8 = 148;
115+
/// Firecracker was shut down after intercepting `SIGBUS`.
116+
pub const FC_EXIT_CODE_SIGBUS: u8 = 149;
117+
/// Firecracker was shut down after intercepting `SIGSEGV`.
118+
pub const FC_EXIT_CODE_SIGSEGV: u8 = 150;
115119

116120
/// Errors associated with the VMM internal logic. These errors cannot be generated by direct user
117121
/// input, but can result from bad configuration of the host (for example if Firecracker doesn't

vmm/src/signal_handler.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extern crate sys_util;
77
use std::io;
88
use std::result::Result;
99

10-
use libc::{_exit, c_int, c_void, siginfo_t, SIGSYS};
10+
use libc::{_exit, c_int, c_void, siginfo_t, SIGBUS, SIGSEGV, SIGSYS};
1111

1212
use logger::{Metric, LOGGER, METRICS};
1313
use sys_util::register_signal_handler;
@@ -53,19 +53,57 @@ extern "C" fn sigsys_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_v
5353
};
5454
}
5555

56+
extern "C" fn sigbus_sigsegv_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
57+
// Safe because we're just reading some fields from a supposedly valid argument.
58+
let si_signo = unsafe { (*info).si_signo };
59+
let si_code = unsafe { (*info).si_code };
60+
61+
// Sanity check. The condition should never be true.
62+
if num != si_signo || (num != SIGBUS && num != SIGSEGV) {
63+
// Safe because we're terminating the process anyway.
64+
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
65+
}
66+
67+
// Other signals which might do async unsafe things incompatible with the rest of this
68+
// function are blocked due to the sa_mask used when registering the signal handler.
69+
error!(
70+
"Shutting down VM after intercepting signal {}, code {}.",
71+
si_signo, si_code
72+
);
73+
// Log the metrics before exiting.
74+
if let Err(e) = LOGGER.log_metrics() {
75+
error!("Failed to log metrics while stopping: {}", e);
76+
}
77+
78+
// Safe because we're terminating the process anyway. We don't actually do anything when
79+
// running unit tests.
80+
#[cfg(not(test))]
81+
unsafe {
82+
_exit(i32::from(match si_signo {
83+
SIGBUS => super::FC_EXIT_CODE_SIGBUS,
84+
SIGSEGV => super::FC_EXIT_CODE_SIGSEGV,
85+
_ => super::FC_EXIT_CODE_UNEXPECTED_ERROR,
86+
}))
87+
};
88+
}
89+
5690
/// Registers all the required signal handlers.
5791
///
58-
/// Custom handlers are installed for: `SIGSYS`.
92+
/// Custom handlers are installed for: `SIGBUS`, `SIGSEGV`, `SIGSYS`.
5993
///
6094
pub fn register_signal_handlers() -> Result<(), io::Error> {
61-
register_signal_handler(SIGSYS, sigsys_handler)
95+
register_signal_handler(SIGSYS, sigsys_handler)?;
96+
register_signal_handler(SIGBUS, sigbus_sigsegv_handler)?;
97+
register_signal_handler(SIGSEGV, sigbus_sigsegv_handler)?;
98+
Ok(())
6299
}
63100

64101
#[cfg(test)]
65102
mod tests {
66103
use super::*;
67104

68105
use std::mem;
106+
use std::process;
69107

70108
use libc::{cpu_set_t, syscall};
71109

@@ -104,6 +142,8 @@ mod tests {
104142
allow_syscall(libc::SYS_brk),
105143
allow_syscall(libc::SYS_exit),
106144
allow_syscall(libc::SYS_futex),
145+
allow_syscall(libc::SYS_getpid),
146+
allow_syscall(libc::SYS_kill),
107147
allow_syscall(libc::SYS_munmap),
108148
allow_syscall(libc::SYS_rt_sigprocmask),
109149
allow_syscall(libc::SYS_rt_sigreturn),
@@ -136,5 +176,11 @@ mod tests {
136176
// The signal handler should let the program continue during unit tests.
137177
assert_eq!(METRICS.seccomp.num_faults.count(), 1);
138178
}
179+
180+
// Assert that the SIGBUS handler left the process alive.
181+
unsafe {
182+
syscall(libc::SYS_kill, process::id(), SIGBUS);
183+
}
184+
assert!(true);
139185
}
140186
}

0 commit comments

Comments
 (0)