use std::os::unix::io::RawFd;
use std::sync::atomic::{AtomicI32, Ordering};
use libc::{_exit, c_int, c_void, siginfo_t, SIGBUS, SIGINT, SIGSEGV, SIGSYS, SIGWINCH};
use utils::signal::register_signal_handler;
const SI_OFF_SYSCALL: isize = 6;
const SYS_SECCOMP_CODE: i32 = 1;
static CONSOLE_SIGWINCH_FD: AtomicI32 = AtomicI32::new(-1);
static CONSOLE_SIGINT_FD: AtomicI32 = AtomicI32::new(-1);
extern "C" fn sigsys_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
let si_signo = unsafe { (*info).si_signo };
let si_code = unsafe { (*info).si_code };
if num != si_signo || num != SIGSYS || si_code != SYS_SECCOMP_CODE {
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
}
let syscall = unsafe { *(info as *const i32).offset(SI_OFF_SYSCALL) as usize };
error!("Shutting down VM after intercepting a bad syscall ({syscall}).");
#[cfg(not(test))]
unsafe {
_exit(i32::from(super::FC_EXIT_CODE_BAD_SYSCALL))
};
}
extern "C" fn sigbus_sigsegv_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
let si_signo = unsafe { (*info).si_signo };
let si_code = unsafe { (*info).si_code };
if num != si_signo || (num != SIGBUS && num != SIGSEGV) {
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
}
error!("Shutting down VM after intercepting signal {si_signo}, code {si_code}.");
#[cfg(not(test))]
unsafe {
_exit(i32::from(match si_signo {
SIGBUS => super::FC_EXIT_CODE_SIGBUS,
SIGSEGV => super::FC_EXIT_CODE_SIGSEGV,
_ => super::FC_EXIT_CODE_UNEXPECTED_ERROR,
}))
};
}
extern "C" fn sigwinch_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
let si_signo = unsafe { (*info).si_signo };
if num != si_signo || num != SIGWINCH {
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
}
let val: u64 = 1;
let console_fd = CONSOLE_SIGWINCH_FD.load(Ordering::Relaxed);
let _ = unsafe { libc::write(console_fd, &val as *const _ as *const c_void, 8) };
}
extern "C" fn sigint_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) {
let si_signo = unsafe { (*info).si_signo };
if num != si_signo || num != SIGINT {
unsafe { _exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
}
let val: u64 = 1;
let console_fd = CONSOLE_SIGINT_FD.load(Ordering::Relaxed);
let _ = unsafe { libc::write(console_fd, &val as *const _ as *const c_void, 8) };
}
pub fn register_sigwinch_handler(console_fd: RawFd) -> utils::errno::Result<()> {
CONSOLE_SIGWINCH_FD.store(console_fd, Ordering::Relaxed);
register_signal_handler(SIGWINCH, sigwinch_handler)?;
Ok(())
}
pub fn register_sigint_handler(sigint_fd: RawFd) -> utils::errno::Result<()> {
CONSOLE_SIGINT_FD.store(sigint_fd, Ordering::Relaxed);
register_signal_handler(SIGINT, sigint_handler)?;
Ok(())
}
pub fn register_signal_handlers() -> utils::errno::Result<()> {
register_signal_handler(SIGSYS, sigsys_handler)?;
register_signal_handler(SIGBUS, sigbus_sigsegv_handler)?;
register_signal_handler(SIGSEGV, sigbus_sigsegv_handler)?;
Ok(())
}