mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: migration seccomp: add plumbing for all migration-related threads
So far, we only have seccomp rules for the postcopy-send thread. This commit introduces the basic plumbing to add seccomp rules also for the migration worker (the migration coordinator) as well as the TCP workers (both, send and receive) in the following. To streamline code setup, all filters are created at a central place early in the migration code. Although this means that some filters are created without the need to do so (e.g., postcopy), this massively simplifies code setup and error handling. This overhead is negligible. On-behalf-of: SAP philipp.schuster@sap.com Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This commit is contained in:
committed by
Bo Chen
parent
e7371984b8
commit
b5c028c286
@@ -65,7 +65,9 @@ use crate::migration::get_vm_snapshot;
|
|||||||
use crate::migration::transport::{
|
use crate::migration::transport::{
|
||||||
self, ReceiveAdditionalConnections, ReceiveListener, SendAdditionalConnections, SocketStream,
|
self, ReceiveAdditionalConnections, ReceiveListener, SendAdditionalConnections, SocketStream,
|
||||||
};
|
};
|
||||||
use crate::migration::worker::{MigrationWorker, MigrationWorkerHandle, MigrationWorkerResult};
|
use crate::migration::worker::{
|
||||||
|
MigrationSeccompFilters, MigrationWorker, MigrationWorkerHandle, MigrationWorkerResult,
|
||||||
|
};
|
||||||
use crate::migration::{recv_vm_config, recv_vm_state};
|
use crate::migration::{recv_vm_config, recv_vm_state};
|
||||||
use crate::seccomp_filters::{Thread, get_seccomp_filter};
|
use crate::seccomp_filters::{Thread, get_seccomp_filter};
|
||||||
use crate::vm::{Error as VmError, Vm, VmState};
|
use crate::vm::{Error as VmError, Vm, VmState};
|
||||||
@@ -1548,7 +1550,7 @@ impl Vmm {
|
|||||||
hypervisor: &dyn hypervisor::Hypervisor,
|
hypervisor: &dyn hypervisor::Hypervisor,
|
||||||
send_data_migration: &VmSendMigrationData,
|
send_data_migration: &VmSendMigrationData,
|
||||||
initial_vm_state: VmState,
|
initial_vm_state: VmState,
|
||||||
seccomp_action: &SeccompAction,
|
seccomp_filters: &MigrationSeccompFilters,
|
||||||
) -> result::Result<(), MigratableError> {
|
) -> result::Result<(), MigratableError> {
|
||||||
// State machine that is updated with more context as we progress.
|
// State machine that is updated with more context as we progress.
|
||||||
let mut ctx = OngoingMigrationContext::new();
|
let mut ctx = OngoingMigrationContext::new();
|
||||||
@@ -1684,15 +1686,17 @@ impl Vmm {
|
|||||||
send_data_migration.tls_dir.as_deref(),
|
send_data_migration.tls_dir.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
let guest_memory = vm.guest_memory();
|
let guest_memory = vm.guest_memory();
|
||||||
// Build the seccomp filter on the parent thread so any failure aborts
|
|
||||||
// the migration before the serve thread is spawned.
|
let seccomp_filters_clone = seccomp_filters.clone();
|
||||||
let seccomp_filter =
|
|
||||||
get_seccomp_filter(seccomp_action, Thread::MigrateSendPostcopy, None)
|
|
||||||
.context("creating postcopy serve seccomp filter")
|
|
||||||
.map_err(MigratableError::MigrateSend)?;
|
|
||||||
let handle = thread::Builder::new()
|
let handle = thread::Builder::new()
|
||||||
.name("migrate-send-postcopy".to_owned())
|
.name("migrate-send-postcopy".to_owned())
|
||||||
.spawn(move || Self::serve_postcopy(seccomp_filter, fault_stream, guest_memory))
|
.spawn(move || {
|
||||||
|
Self::serve_postcopy(
|
||||||
|
&seccomp_filters_clone.postcopy_server,
|
||||||
|
fault_stream,
|
||||||
|
guest_memory,
|
||||||
|
)
|
||||||
|
})
|
||||||
.context("spawning postcopy serve thread")
|
.context("spawning postcopy serve thread")
|
||||||
.map_err(MigratableError::MigrateSend)?;
|
.map_err(MigratableError::MigrateSend)?;
|
||||||
Some(handle)
|
Some(handle)
|
||||||
@@ -1773,7 +1777,7 @@ impl Vmm {
|
|||||||
reason = "runs on a dedicated thread and must own its arguments"
|
reason = "runs on a dedicated thread and must own its arguments"
|
||||||
)]
|
)]
|
||||||
fn serve_postcopy(
|
fn serve_postcopy(
|
||||||
seccomp_filter: BpfProgram,
|
seccomp_filter: &BpfProgram,
|
||||||
mut socket: SocketStream,
|
mut socket: SocketStream,
|
||||||
guest_memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
guest_memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
) -> result::Result<(), MigratableError> {
|
) -> result::Result<(), MigratableError> {
|
||||||
@@ -1781,7 +1785,7 @@ impl Vmm {
|
|||||||
// seccomp is disabled (SeccompAction::Allow), in which case there is
|
// seccomp is disabled (SeccompAction::Allow), in which case there is
|
||||||
// nothing to apply.
|
// nothing to apply.
|
||||||
if !seccomp_filter.is_empty() {
|
if !seccomp_filter.is_empty() {
|
||||||
apply_filter(&seccomp_filter)
|
apply_filter(seccomp_filter)
|
||||||
.context("applying postcopy serve seccomp filter")
|
.context("applying postcopy serve seccomp filter")
|
||||||
.map_err(MigratableError::MigrateSend)?;
|
.map_err(MigratableError::MigrateSend)?;
|
||||||
}
|
}
|
||||||
@@ -3144,6 +3148,21 @@ impl RequestHandler for Vmm {
|
|||||||
.with_context(|| "Failed to clone check_migration_evt FD")
|
.with_context(|| "Failed to clone check_migration_evt FD")
|
||||||
.map_err(MigratableError::MigrateSend)?;
|
.map_err(MigratableError::MigrateSend)?;
|
||||||
|
|
||||||
|
// We are creating all seccomp filters beforehand, as:
|
||||||
|
// - this simplifies the code (especially error propagation)
|
||||||
|
// - the overhead is negligible
|
||||||
|
let seccomp_filters = {
|
||||||
|
let postcopy_server =
|
||||||
|
get_seccomp_filter(&self.seccomp_action, Thread::MigrateSendPostcopy, None)
|
||||||
|
.map_err(|e| {
|
||||||
|
MigratableError::MigrateSend(anyhow!(
|
||||||
|
"creating postcopy serve seccomp filter: {e}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
MigrationSeccompFilters { postcopy_server }
|
||||||
|
};
|
||||||
|
|
||||||
// Take VM ownership. This also means that API events can no longer
|
// Take VM ownership. This also means that API events can no longer
|
||||||
// change the VM (e.g. net device hotplug).
|
// change the VM (e.g. net device hotplug).
|
||||||
let vm = self
|
let vm = self
|
||||||
@@ -3160,7 +3179,7 @@ impl RequestHandler for Vmm {
|
|||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
self.hypervisor.clone(),
|
self.hypervisor.clone(),
|
||||||
initial_vm_state,
|
initial_vm_state,
|
||||||
self.seccomp_action.clone(),
|
seccomp_filters,
|
||||||
) {
|
) {
|
||||||
Ok(handle) => {
|
Ok(handle) => {
|
||||||
self.vm = VmOwnership::Migration {
|
self.vm = VmOwnership::Migration {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use std::{io, thread};
|
|||||||
|
|
||||||
use event_monitor::event;
|
use event_monitor::event;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use seccompiler::SeccompAction;
|
use seccompiler::BpfProgram;
|
||||||
use vm_migration::MigratableError;
|
use vm_migration::MigratableError;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
@@ -68,6 +68,11 @@ impl Drop for MigrationWorkerHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MigrationSeccompFilters {
|
||||||
|
pub postcopy_server: BpfProgram,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MigrationWorker {
|
pub struct MigrationWorker {
|
||||||
// Keep the VM out of the thread closure until spawning succeeds.
|
// Keep the VM out of the thread closure until spawning succeeds.
|
||||||
vm_receiver: Receiver<Vm>,
|
vm_receiver: Receiver<Vm>,
|
||||||
@@ -76,7 +81,7 @@ pub struct MigrationWorker {
|
|||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||||
initial_vm_state: VmState,
|
initial_vm_state: VmState,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_filters: MigrationSeccompFilters,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MigrationWorker {
|
impl MigrationWorker {
|
||||||
@@ -92,7 +97,7 @@ impl MigrationWorker {
|
|||||||
self.hypervisor.as_ref(),
|
self.hypervisor.as_ref(),
|
||||||
&self.config,
|
&self.config,
|
||||||
self.initial_vm_state,
|
self.initial_vm_state,
|
||||||
&self.seccomp_action,
|
&self.seccomp_filters,
|
||||||
)
|
)
|
||||||
.inspect(|_| event!("vm", "migration-finished"))
|
.inspect(|_| event!("vm", "migration-finished"))
|
||||||
.inspect_err(|_| event!("vm", "migration-failed"));
|
.inspect_err(|_| event!("vm", "migration-failed"));
|
||||||
@@ -119,7 +124,7 @@ impl MigrationWorker {
|
|||||||
dyn hypervisor::Hypervisor,
|
dyn hypervisor::Hypervisor,
|
||||||
>,
|
>,
|
||||||
initial_vm_state: VmState,
|
initial_vm_state: VmState,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_filters: MigrationSeccompFilters,
|
||||||
) -> Result<MigrationWorkerHandle, MigrationWorkerSpawnError> {
|
) -> Result<MigrationWorkerHandle, MigrationWorkerSpawnError> {
|
||||||
let (vm_sender, vm_receiver) = mpsc::sync_channel(0);
|
let (vm_sender, vm_receiver) = mpsc::sync_channel(0);
|
||||||
let worker = MigrationWorker {
|
let worker = MigrationWorker {
|
||||||
@@ -129,7 +134,7 @@ impl MigrationWorker {
|
|||||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
hypervisor,
|
hypervisor,
|
||||||
initial_vm_state,
|
initial_vm_state,
|
||||||
seccomp_action,
|
seccomp_filters,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inner_handle = match thread::Builder::new()
|
let inner_handle = match thread::Builder::new()
|
||||||
|
|||||||
Reference in New Issue
Block a user