diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 04be456c2..f9d81fbd2 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -980,7 +980,12 @@ impl Vmm { // The accept thread hands the page fault connection back via this channel. let (fault_tx, fault_rx) = channel(); let connections = listener.try_clone().and_then(|l| { - ReceiveAdditionalConnections::new(l, guest_memory.clone(), fault_tx) + ReceiveAdditionalConnections::new( + l, + guest_memory.clone(), + fault_tx, + &self.seccomp_action, + ) })?; Ok(ReceiveMigrationConfiguredData { memory_manager, @@ -1652,6 +1657,7 @@ impl Vmm { send_data_migration.connections, send_data_migration.tls_dir.as_deref(), &vm.guest_memory(), + &seccomp_filters.tcp_worker, )?; Self::do_memory_migration( @@ -3159,6 +3165,16 @@ impl RequestHandler for Vmm { )) })?; + let tcp_worker = + get_seccomp_filter(&self.seccomp_action, Thread::MigrationTcpWorker, None) + .map_err(|e| { + MigratableError::MigrateSend(anyhow!( + "Error creating migration TCP worker seccomp filter: {e}" + )) + })?; + + // Build the seccomp filter on the parent thread so any failure aborts + // the migration before the serve thread is spawned. let postcopy_server = get_seccomp_filter(&self.seccomp_action, Thread::MigrateSendPostcopy, None) .map_err(|e| { @@ -3169,6 +3185,7 @@ impl RequestHandler for Vmm { MigrationSeccompFilters { worker, + tcp_worker, postcopy_server, } }; diff --git a/vmm/src/migration/transport.rs b/vmm/src/migration/transport.rs index b23fec3b3..f5f490b29 100644 --- a/vmm/src/migration/transport.rs +++ b/vmm/src/migration/transport.rs @@ -18,6 +18,7 @@ use std::{mem, thread}; use anyhow::{Context, anyhow}; use log::{debug, error, info, warn}; +use seccompiler::{BpfProgram, SeccompAction, apply_filter}; use serde_json; use thiserror::Error; use vm_memory::bitmap::BitmapSlice; @@ -30,6 +31,7 @@ use vm_migration::tls::{TlsServerConfig, TlsStream}; use vm_migration::{MigratableError, Snapshot}; use vmm_sys_util::eventfd::EventFd; +use crate::seccomp_filters::{Thread, get_seccomp_filter}; use crate::sync_utils::Gate; use crate::{GuestMemoryMmap, VmMigrationConfig}; @@ -308,6 +310,7 @@ impl ReceiveAdditionalConnections { listener: ReceiveListener, guest_memory: GuestMemoryAtomic, fault_tx: Sender, + seccomp_action: &SeccompAction, ) -> Result { let event_fd = EventFd::new(0) .context("Error creating terminate fd") @@ -318,10 +321,26 @@ impl ReceiveAdditionalConnections { .context("Error cloning terminate fd") .map_err(MigratableError::MigrateReceive)?; + let seccomp_filter = get_seccomp_filter(seccomp_action, Thread::MigrationTcpWorker, None) + .context("Error creating migration TCP worker seccomp filter") + .map_err(MigratableError::MigrateReceive)?; + let accept_thread = thread::Builder::new() .name("migrate-receive-accept-connections".to_owned()) .spawn(move || { - Self::accept_connections(listener, &terminate_fd, &guest_memory, &fault_tx) + if !seccomp_filter.is_empty() { + apply_filter(&seccomp_filter) + .context("Error applying migration TCP worker seccomp filter") + .map_err(MigratableError::MigrateReceive)?; + } + + Self::accept_connections( + listener, + &terminate_fd, + &guest_memory, + &fault_tx, + &seccomp_filter, + ) }) .context("Error creating connection accept thread") .map_err(MigratableError::MigrateReceive)?; @@ -348,6 +367,7 @@ impl ReceiveAdditionalConnections { terminate_fd: &EventFd, guest_memory: &GuestMemoryAtomic, fault_tx: &Sender, + seccomp_filter: &BpfProgram, ) -> Result<(), MigratableError> { let mut threads = Vec::new(); let first_err = Self::accept_connections_loop( @@ -356,6 +376,7 @@ impl ReceiveAdditionalConnections { guest_memory, fault_tx, &mut threads, + seccomp_filter, ); if first_err.is_err() { @@ -380,6 +401,7 @@ impl ReceiveAdditionalConnections { guest_memory: &GuestMemoryAtomic, fault_tx: &Sender, threads: &mut Vec>>, + seccomp_filter: &BpfProgram, ) -> Result<(), MigratableError> { loop { let socket = listener.abortable_accept(terminate_fd)?; @@ -402,6 +424,7 @@ impl ReceiveAdditionalConnections { threads.len(), terminate_fd, guest_memory.clone(), + seccomp_filter, )?; threads.push(thread); } @@ -456,15 +479,24 @@ impl ReceiveAdditionalConnections { index: usize, terminate_fd: &EventFd, guest_memory: GuestMemoryAtomic, + seccomp_filter: &BpfProgram, ) -> Result>, MigratableError> { let terminate_fd = terminate_fd .try_clone() .context("Error cloning terminate fd") .map_err(MigratableError::MigrateReceive)?; + let seccomp_filter_t = seccomp_filter.clone(); thread::Builder::new() .name(format!("migrate-receive-memory-{index}")) - .spawn(move || Self::worker_receive_memory(&mut socket, &terminate_fd, &guest_memory)) + .spawn(move || { + if !seccomp_filter_t.is_empty() { + apply_filter(&seccomp_filter_t) + .context("Error applying migration TCP worker seccomp filter") + .map_err(MigratableError::MigrateReceive)?; + } + Self::worker_receive_memory(&mut socket, &terminate_fd, &guest_memory) + }) .map_err(|e| { error!("Error spawning receive-memory thread: {e}"); MigratableError::MigrateReceive( @@ -652,6 +684,7 @@ impl SendAdditionalConnections { connections: NonZeroU32, tls_dir: Option<&Path>, guest_memory: &GuestMemoryAtomic, + seccomp_filter: &BpfProgram, ) -> Result { let mut threads = Vec::new(); let configured_connections = connections.get(); @@ -683,10 +716,17 @@ impl SendAdditionalConnections { let message_rx = message_rx.clone(); let worker_error = worker_error.clone(); let notify_tx = notify_tx.clone(); + let seccomp_filter = seccomp_filter.clone(); let thread = thread::Builder::new() .name(format!("migrate-send-memory-{n}")) .spawn(move || { + if !seccomp_filter.is_empty() { + apply_filter(&seccomp_filter) + .context("Error applying migration TCP worker seccomp filter") + .map_err(MigratableError::MigrateReceive)?; + } + Self::worker_send_memory( &mut socket, &guest_memory, diff --git a/vmm/src/migration/worker.rs b/vmm/src/migration/worker.rs index 0fc94ef83..d2b4a78cf 100644 --- a/vmm/src/migration/worker.rs +++ b/vmm/src/migration/worker.rs @@ -72,6 +72,7 @@ impl Drop for MigrationWorkerHandle { #[derive(Clone, Debug)] pub struct MigrationSeccompFilters { pub worker: BpfProgram, + pub tcp_worker: BpfProgram, pub postcopy_server: BpfProgram, } diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index 72336fe42..dc167f8cd 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -39,7 +39,11 @@ pub enum Thread { #[cfg(feature = "dbus_api")] DBusApi, EventMonitor, + /// Thread handling the migration on the sending side. MigrationWorker, + /// Key used for the TCP workers for send and receive, as well as the accept + /// thread on the receiver side. + MigrationTcpWorker, SignalHandler, Vcpu, Vmm, @@ -1124,6 +1128,52 @@ fn migration_thread_rules() -> Result)>, BackendError ]) } +fn migration_tcp_worker_thread_rules() -> Result)>, BackendError> { + Ok(vec![ + (libc::SYS_accept4, vec![]), + (libc::SYS_brk, vec![]), + (libc::SYS_clock_gettime, vec![]), + (libc::SYS_clone, vec![]), + (libc::SYS_clone3, vec![]), + (libc::SYS_close, vec![]), + (libc::SYS_exit, vec![]), + (libc::SYS_exit_group, vec![]), + (libc::SYS_fcntl, vec![]), + (libc::SYS_futex, vec![]), + (libc::SYS_getrandom, vec![]), + (libc::SYS_gettid, vec![]), + (libc::SYS_madvise, vec![]), + (libc::SYS_mmap, vec![]), + (libc::SYS_mprotect, vec![]), + (libc::SYS_munmap, 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_pwrite64, vec![]), + (libc::SYS_read, vec![]), + (libc::SYS_readv, 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![]), + // We are already inheriting seccomp from the parent thread. + (libc::SYS_seccomp, vec![]), + (libc::SYS_sendmsg, vec![]), + (libc::SYS_sendto, vec![]), + (libc::SYS_set_robust_list, vec![]), + (libc::SYS_setsockopt, vec![]), + (libc::SYS_sigaltstack, vec![]), + (libc::SYS_write, vec![]), + (libc::SYS_writev, vec![]), + ]) +} + fn serial_manager_thread_rules() -> Result)>, BackendError> { Ok(vec![ (libc::SYS_accept4, vec![]), @@ -1193,6 +1243,7 @@ fn get_seccomp_rules( Thread::DBusApi => dbus_api_thread_rules()?, Thread::EventMonitor => event_monitor_thread_rules()?, Thread::MigrationWorker => migration_thread_rules()?, + Thread::MigrationTcpWorker => migration_tcp_worker_thread_rules()?, Thread::SerialManager => serial_manager_thread_rules()?, Thread::SignalHandler => signal_handler_thread_rules()?, Thread::Vcpu => vcpu_thread_rules(