From c1f555cde36c07fa86101a28225e8af6f7f13a1d Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 23 Mar 2023 17:10:19 +0000 Subject: [PATCH] vmm: fall back if CLONE_CLEAR_SIGHAND unsupported This will allow the SIGWINCH listener to run on kernels older than 5.5, although on those kernels it will have to make 64 syscalls to reset all the signal handlers. Signed-off-by: Alyssa Ross --- arch/src/aarch64/mod.rs | 2 ++ arch/src/lib.rs | 4 +-- arch/src/x86_64/mod.rs | 2 ++ vmm/src/sigwinch_listener.rs | 47 +++++++++++++++++++++++++++--------- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/arch/src/aarch64/mod.rs b/arch/src/aarch64/mod.rs index afc051489..124b8cbe9 100644 --- a/arch/src/aarch64/mod.rs +++ b/arch/src/aarch64/mod.rs @@ -21,6 +21,8 @@ use std::fmt::Debug; use std::sync::{Arc, Mutex}; use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize}; +pub const _NSIG: i32 = 65; + /// Errors thrown while configuring aarch64 system. #[derive(Debug)] pub enum Error { diff --git a/arch/src/lib.rs b/arch/src/lib.rs index dc1f90d95..62cd1df6c 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -82,7 +82,7 @@ pub mod aarch64; pub use aarch64::{ arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt, get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, - layout::IRQ_BASE, uefi, EntryPoint, + layout::IRQ_BASE, uefi, EntryPoint, _NSIG, }; #[cfg(target_arch = "x86_64")] @@ -92,7 +92,7 @@ pub mod x86_64; pub use x86_64::{ arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid, get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, - layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, + layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG, }; /// Safe wrapper for `sysconf(_SC_PAGESIZE)`. diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index aacacd06e..3bdc01ee7 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -53,6 +53,8 @@ const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10; #[cfg(feature = "tdx")] const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5; +pub const _NSIG: i32 = 65; + #[derive(Debug, Copy, Clone)] /// Specifies the entry point address where the guest must start /// executing code, as well as which of the supported boot protocols diff --git a/vmm/src/sigwinch_listener.rs b/vmm/src/sigwinch_listener.rs index d789bc445..cad87f883 100644 --- a/vmm/src/sigwinch_listener.rs +++ b/vmm/src/sigwinch_listener.rs @@ -2,10 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use crate::clone3::{clone3, clone_args, CLONE_CLEAR_SIGHAND}; +use arch::_NSIG; use libc::{ - c_int, c_void, close, getpgrp, ioctl, pipe2, poll, pollfd, setsid, sigemptyset, siginfo_t, - sigprocmask, syscall, tcsetpgrp, SYS_close_range, ENOSYS, O_CLOEXEC, POLLERR, SIGWINCH, - SIG_SETMASK, STDERR_FILENO, TIOCSCTTY, + c_int, c_void, close, fork, getpgrp, ioctl, pipe2, poll, pollfd, setsid, sigemptyset, + siginfo_t, signal, sigprocmask, syscall, tcsetpgrp, SYS_close_range, EINVAL, ENOSYS, O_CLOEXEC, + POLLERR, SIGWINCH, SIG_DFL, SIG_SETMASK, STDERR_FILENO, TIOCSCTTY, }; use seccompiler::{apply_filter, BpfProgram}; use std::cell::RefCell; @@ -176,6 +177,35 @@ fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, pty: File) -> ! exit(0); } +/// # Safety +/// +/// Same as [`fork`]. +unsafe fn clone_clear_sighand() -> io::Result { + let mut args = clone_args::default(); + args.flags |= CLONE_CLEAR_SIGHAND; + let r = clone3(&mut args, size_of::()); + if r != -1 { + return Ok(r.try_into().unwrap()); + } + let e = io::Error::last_os_error(); + if e.raw_os_error() != Some(ENOSYS) && e.raw_os_error() != Some(EINVAL) { + return Err(e); + } + + // If CLONE_CLEAR_SIGHAND isn't available, fall back to resetting + // all the signal handlers one by one. + let r = fork(); + if r == -1 { + return Err(io::Error::last_os_error()); + } + if r == 0 { + for signum in 1.._NSIG { + let _ = signal(signum, SIG_DFL); + } + } + Ok(r.try_into().unwrap()) +} + pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, tty_sub: File) -> io::Result { let mut pipe = [-1; 2]; // SAFETY: FFI call with valid arguments @@ -188,16 +218,9 @@ pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, tty_sub: File) -> io: // SAFETY: pipe[1] is valid let tx = unsafe { File::from_raw_fd(pipe[1]) }; - let mut args = clone_args::default(); - args.flags |= CLONE_CLEAR_SIGHAND; - // SAFETY: FFI call - match unsafe { clone3(&mut args, size_of::()) } { - -1 => return Err(io::Error::last_os_error()), - 0 => { - sigwinch_listener_main(seccomp_filter, tx, tty_sub); - } - _ => (), + if unsafe { clone_clear_sighand() }? == 0 { + sigwinch_listener_main(seccomp_filter, tx, tty_sub); } drop(tx);