From fd88e23ecb83eaecbaae45e8e31e0f60319eb7b7 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 24 Jun 2026 21:37:44 +0200 Subject: [PATCH] vmm: migration seccomp: add for migration worker (coordinator thread) On-behalf-of: SAP philipp.schuster@sap.com Signed-off-by: Philipp Schuster --- vmm/src/lib.rs | 12 ++++++- vmm/src/migration/worker.rs | 43 +++++++++++++++++-------- vmm/src/seccomp_filters.rs | 62 +++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 14 deletions(-) diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 46bca24cb..04be456c2 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -3152,6 +3152,13 @@ impl RequestHandler for Vmm { // - this simplifies the code (especially error propagation) // - the overhead is negligible let seccomp_filters = { + let worker = get_seccomp_filter(&self.seccomp_action, Thread::MigrationWorker, None) + .map_err(|e| { + MigratableError::MigrateSend(anyhow!( + "Error creating migration seccomp filter: {e}" + )) + })?; + let postcopy_server = get_seccomp_filter(&self.seccomp_action, Thread::MigrateSendPostcopy, None) .map_err(|e| { @@ -3160,7 +3167,10 @@ impl RequestHandler for Vmm { )) })?; - MigrationSeccompFilters { postcopy_server } + MigrationSeccompFilters { + worker, + postcopy_server, + } }; // Take VM ownership. This also means that API events can no longer diff --git a/vmm/src/migration/worker.rs b/vmm/src/migration/worker.rs index 7ff48eaec..0fc94ef83 100644 --- a/vmm/src/migration/worker.rs +++ b/vmm/src/migration/worker.rs @@ -19,9 +19,10 @@ use std::sync::mpsc::{self, Receiver}; use std::thread::JoinHandle; use std::{io, thread}; +use anyhow::anyhow; use event_monitor::event; use log::warn; -use seccompiler::BpfProgram; +use seccompiler::{BpfProgram, apply_filter}; use vm_migration::MigratableError; use vmm_sys_util::eventfd::EventFd; @@ -70,6 +71,7 @@ impl Drop for MigrationWorkerHandle { #[derive(Clone, Debug)] pub struct MigrationSeccompFilters { + pub worker: BpfProgram, pub postcopy_server: BpfProgram, } @@ -88,26 +90,41 @@ impl MigrationWorker { /// Drives the migration from its start to its end (success, cancellation, /// failure) fn run(self) -> MigrationWorkerResult { + let seccomp_res = if self.seccomp_filters.worker.is_empty() { + Ok(()) + } else { + apply_filter(&self.seccomp_filters.worker).map_err(|e| { + MigratableError::MigrateSend(anyhow!( + "Error applying migration seccomp filter: {e}" + )) + }) + }; + let mut vm = self.vm_receiver.recv().expect("VMM should send VM"); - event!("vm", "migration-started"); - let res = Vmm::send_migration( - &mut vm, - #[cfg(all(feature = "kvm", target_arch = "x86_64"))] - self.hypervisor.as_ref(), - &self.config, - self.initial_vm_state, - &self.seccomp_filters, - ) - .inspect(|_| event!("vm", "migration-finished")) - .inspect_err(|_| event!("vm", "migration-failed")); + // We can't propagate errors early because of the complex return type, + // therefore we chain the results together. + let migration_result = seccomp_res + .and_then(|()| { + event!("vm", "migration-started"); + Vmm::send_migration( + &mut vm, + #[cfg(all(feature = "kvm", target_arch = "x86_64"))] + self.hypervisor.as_ref(), + &self.config, + self.initial_vm_state, + &self.seccomp_filters, + ) + }) + .inspect(|_| event!("vm", "migration-finished")) + .inspect_err(|_| event!("vm", "migration-failed")); // Notify VMM thread to check migration result. self.check_migration_evt.write(1).unwrap(); MigrationWorkerResult { vm, - migration_result: res, + migration_result, initial_vm_state: self.initial_vm_state, } } diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index eb76c7697..72336fe42 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -39,6 +39,7 @@ pub enum Thread { #[cfg(feature = "dbus_api")] DBusApi, EventMonitor, + MigrationWorker, SignalHandler, Vcpu, Vmm, @@ -1063,6 +1064,66 @@ fn event_monitor_thread_rules() -> Result)>, BackendE ]) } +fn migration_thread_rules() -> Result)>, BackendError> { + Ok(vec![ + (libc::SYS_accept4, vec![]), + (libc::SYS_brk, vec![]), + (libc::SYS_clock_gettime, vec![]), + (libc::SYS_clock_nanosleep, vec![]), + (libc::SYS_clone, vec![]), + (libc::SYS_clone3, vec![]), + (libc::SYS_close, vec![]), + (libc::SYS_connect, vec![]), + (libc::SYS_exit, vec![]), + (libc::SYS_exit_group, vec![]), + (libc::SYS_fcntl, vec![]), + (libc::SYS_fstat, vec![]), + (libc::SYS_ftruncate, vec![]), + (libc::SYS_futex, vec![]), + (libc::SYS_getpid, vec![]), + (libc::SYS_getrandom, vec![]), + (libc::SYS_gettid, vec![]), + (libc::SYS_ioctl, vec![]), + (libc::SYS_lseek, vec![]), + (libc::SYS_madvise, vec![]), + (libc::SYS_memfd_create, vec![]), + (libc::SYS_mmap, vec![]), + (libc::SYS_mprotect, vec![]), + (libc::SYS_mremap, vec![]), + (libc::SYS_munmap, vec![]), + (libc::SYS_nanosleep, vec![]), + (libc::SYS_openat, vec![]), + #[cfg(target_arch = "x86_64")] + (libc::SYS_poll, vec![]), + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + (libc::SYS_ppoll, vec![]), + (libc::SYS_prctl, vec![]), + (libc::SYS_read, vec![]), + (libc::SYS_readv, vec![]), + (libc::SYS_tkill, vec![]), + (libc::SYS_recvfrom, vec![]), + (libc::SYS_recvmsg, vec![]), + (libc::SYS_rseq, vec![]), + (libc::SYS_rt_sigprocmask, vec![]), + (libc::SYS_rt_sigreturn, vec![]), + (libc::SYS_sched_getaffinity, vec![]), + (libc::SYS_sched_yield, vec![]), + (libc::SYS_seccomp, vec![]), + (libc::SYS_sendmsg, vec![]), + (libc::SYS_setsockopt, vec![]), + (libc::SYS_sendto, vec![]), + (libc::SYS_set_robust_list, vec![]), + (libc::SYS_sigaltstack, vec![]), + (libc::SYS_socket, vec![]), + (libc::SYS_socketpair, vec![]), + (libc::SYS_statx, vec![]), + (libc::SYS_tgkill, vec![]), + (libc::SYS_timerfd_settime, vec![]), + (libc::SYS_write, vec![]), + (libc::SYS_writev, vec![]), + ]) +} + fn serial_manager_thread_rules() -> Result)>, BackendError> { Ok(vec![ (libc::SYS_accept4, vec![]), @@ -1131,6 +1192,7 @@ fn get_seccomp_rules( #[cfg(feature = "dbus_api")] Thread::DBusApi => dbus_api_thread_rules()?, Thread::EventMonitor => event_monitor_thread_rules()?, + Thread::MigrationWorker => migration_thread_rules()?, Thread::SerialManager => serial_manager_thread_rules()?, Thread::SignalHandler => signal_handler_thread_rules()?, Thread::Vcpu => vcpu_thread_rules(