Skip to content

Commit 0f7942d

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 fd6428f commit 0f7942d

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-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

+48-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,49 @@ 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)]
@@ -104,6 +141,8 @@ mod tests {
104141
allow_syscall(libc::SYS_brk),
105142
allow_syscall(libc::SYS_exit),
106143
allow_syscall(libc::SYS_futex),
144+
allow_syscall(libc::SYS_getpid),
145+
allow_syscall(libc::SYS_kill),
107146
allow_syscall(libc::SYS_munmap),
108147
allow_syscall(libc::SYS_rt_sigprocmask),
109148
allow_syscall(libc::SYS_rt_sigreturn),
@@ -136,5 +175,11 @@ mod tests {
136175
// The signal handler should let the program continue during unit tests.
137176
assert_eq!(METRICS.seccomp.num_faults.count(), 1);
138177
}
178+
179+
// Assert that the SIGBUS handler left the process alive.
180+
unsafe {
181+
syscall(libc::SYS_kill, process::id(), SIGBUS);
182+
}
183+
assert!(true);
139184
}
140185
}

0 commit comments

Comments
 (0)