Skip to content

Commit 76d668e

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 c751e4d commit 76d668e

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

vmm/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ pub const FC_EXIT_CODE_GENERIC_ERROR: u8 = 1;
113113
pub const FC_EXIT_CODE_UNEXPECTED_ERROR: u8 = 2;
114114
/// Firecracker was shut down after intercepting a restricted system call.
115115
pub const FC_EXIT_CODE_BAD_SYSCALL: u8 = 148;
116+
/// Firecracker was shut down after intercepting `SIGBUS`.
117+
pub const FC_EXIT_CODE_SIGBUS: u8 = 149;
118+
/// Firecracker was shut down after intercepting `SIGSEGV`.
119+
pub const FC_EXIT_CODE_SIGSEGV: u8 = 150;
116120

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

vmm/src/signal_handler.rs

+41-3
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,12 +53,45 @@ 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+
60+
// Sanity check. The condition should never be true.
61+
if num != si_signo || (num != SIGBUS && num != SIGSEGV) {
62+
// Safe because we're terminating the process anyway.
63+
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
64+
}
65+
66+
// Other signals which might do async unsafe things incompatible with the rest of this
67+
// function are blocked due to the sa_mask used when registering the signal handler.
68+
error!("Shutting down VM after intercepting signal {}.", si_signo);
69+
// Log the metrics before exiting.
70+
if let Err(e) = LOGGER.log_metrics() {
71+
error!("Failed to log metrics while stopping: {}", e);
72+
}
73+
74+
// Safe because we're terminating the process anyway. We don't actually do anything when
75+
// running unit tests.
76+
#[cfg(not(test))]
77+
unsafe {
78+
_exit(i32::from(match si_signo {
79+
SIGBUS => super::FC_EXIT_CODE_SIGBUS,
80+
SIGSEGV => super::FC_EXIT_CODE_SIGSEGV,
81+
_ => super::FC_EXIT_CODE_UNEXPECTED_ERROR,
82+
}))
83+
};
84+
}
85+
5686
/// Registers all the required signal handlers.
5787
///
58-
/// Custom handlers are installed for: `SIGSYS`.
88+
/// Custom handlers are installed for: `SIGBUS`, `SIGSEGV`, `SIGSYS`.
5989
///
6090
pub fn register_signal_handlers() -> Result<(), io::Error> {
61-
register_signal_handler(SIGSYS, sigsys_handler)
91+
register_signal_handler(SIGSYS, sigsys_handler)?;
92+
register_signal_handler(SIGBUS, sigbus_sigsegv_handler)?;
93+
register_signal_handler(SIGSEGV, sigbus_sigsegv_handler)?;
94+
Ok(())
6295
}
6396

6497
#[cfg(test)]
@@ -137,5 +170,10 @@ mod tests {
137170
// The signal handler should let the program continue during unit tests.
138171
assert_eq!(METRICS.seccomp.num_faults.count(), 1);
139172
}
173+
174+
// Assert that the SIGSEGV handler left the process alive.
175+
let foo = 0 as *const i32;
176+
let _bar = unsafe { *foo };
177+
assert!(true);
140178
}
141179
}

0 commit comments

Comments
 (0)