From 54e523c302984f3ae20b90908350a113186ee8c8 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 3 Sep 2021 11:43:30 +0100 Subject: [PATCH] virtio-devices: Use a common method for spawning virtio threads Introduce a common solution for spawning the virtio threads which will make it easier to add the panic handling. During this effort I discovered that there were no seccomp filters registered for the vhost-user-net thread nor the vhost-user-block thread. This change also incorporates basic seccomp filters for those as part of the refactoring. Signed-off-by: Rob Bradford --- virtio-devices/src/balloon.rs | 33 +++++--------- virtio-devices/src/block.rs | 34 +++++---------- virtio-devices/src/console.rs | 38 ++++++---------- virtio-devices/src/iommu.rs | 39 ++++++----------- virtio-devices/src/lib.rs | 1 + virtio-devices/src/mem.rs | 33 +++++--------- virtio-devices/src/net.rs | 62 ++++++++++---------------- virtio-devices/src/pmem.rs | 34 +++++---------- virtio-devices/src/rng.rs | 33 +++++--------- virtio-devices/src/seccomp_filters.rs | 63 +++++++++++++++++++++++++++ virtio-devices/src/thread_helper.rs | 43 ++++++++++++++++++ virtio-devices/src/vhost_user/blk.rs | 39 +++++++++++------ virtio-devices/src/vhost_user/fs.rs | 36 ++++++--------- virtio-devices/src/vhost_user/net.rs | 59 +++++++++++-------------- virtio-devices/src/vsock/device.rs | 40 +++++++---------- virtio-devices/src/watchdog.rs | 33 +++++--------- vmm/src/device_manager.rs | 7 ++- 17 files changed, 311 insertions(+), 316 deletions(-) create mode 100644 virtio-devices/src/thread_helper.rs diff --git a/virtio-devices/src/balloon.rs b/virtio-devices/src/balloon.rs index 84dd0f5f7..2260d753d 100644 --- a/virtio-devices/src/balloon.rs +++ b/virtio-devices/src/balloon.rs @@ -16,11 +16,12 @@ use super::{ ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{VirtioInterrupt, VirtioInterruptType}; use libc::EFD_NONBLOCK; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::io; use std::mem::size_of; use std::os::unix::io::AsRawFd; @@ -28,7 +29,6 @@ use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::mpsc; use std::sync::{Arc, Barrier, Mutex}; -use std::thread; use vm_memory::GuestMemory; use vm_memory::{ Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, @@ -460,27 +460,18 @@ impl VirtioDevice for Balloon { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - let virtio_balloon_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioBalloon) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_balloon_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_balloon_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioBalloon, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone virtio-balloon epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); event!("virtio-device", "activated", "id", &self.id); diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index dcad38a65..539214aa9 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -14,7 +14,8 @@ use super::{ RateLimiterConfig, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; use block_util::{ @@ -22,7 +23,7 @@ use block_util::{ RequestType, VirtioBlockConfig, }; use rate_limiter::{RateLimiter, TokenType}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::io; use std::num::Wrapping; use std::os::unix::io::AsRawFd; @@ -30,7 +31,6 @@ use std::path::PathBuf; use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Barrier}; -use std::thread; use std::{collections::HashMap, convert::TryInto}; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; @@ -588,29 +588,17 @@ impl VirtioDevice for Block { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); - // Retrieve seccomp filter for virtio_block thread - let virtio_block_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioBlock) - .map_err(ActivateError::CreateSeccompFilter)?; - - thread::Builder::new() - .name(format!("{}_q{}", self.id.clone(), i)) - .spawn(move || { - if !virtio_block_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_block_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + spawn_virtio_thread( + &format!("{}_q{}", self.id.clone(), i), + &self.seccomp_action, + Thread::VirtioBlock, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the virtio-block epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; } self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/console.rs b/virtio-devices/src/console.rs index 81a3425ce..c1ee0aade 100644 --- a/virtio-devices/src/console.rs +++ b/virtio-devices/src/console.rs @@ -3,15 +3,16 @@ use super::Error as DeviceError; use super::{ - ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, - VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, + ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon, + VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; use libc::EFD_NONBLOCK; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::cmp; use std::collections::VecDeque; use std::fs::File; @@ -21,7 +22,6 @@ use std::os::unix::io::AsRawFd; use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Barrier, Mutex}; -use std::thread; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; use vm_memory::{ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic}; @@ -467,28 +467,18 @@ impl VirtioDevice for Console { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_console thread - let virtio_console_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioConsole) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_console_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_console_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioConsole, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the virtio-console epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/iommu.rs b/virtio-devices/src/iommu.rs index f750e326b..96004d482 100644 --- a/virtio-devices/src/iommu.rs +++ b/virtio-devices/src/iommu.rs @@ -4,14 +4,14 @@ use super::Error as DeviceError; use super::{ - ActivateError, ActivateResult, DescriptorChain, EpollHelper, EpollHelperError, - EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, - EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, + ActivateResult, DescriptorChain, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, + VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{DmaRemapping, VirtioInterrupt, VirtioInterruptType}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::collections::BTreeMap; use std::fmt::{self, Display}; use std::io; @@ -21,7 +21,6 @@ use std::os::unix::io::AsRawFd; use std::result; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Barrier, RwLock}; -use std::thread; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; use vm_device::dma_mapping::ExternalDmaMapping; @@ -843,29 +842,17 @@ impl VirtioDevice for Iommu { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_iommu thread - let virtio_iommu_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioIommu) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_iommu_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_iommu_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } - + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioIommu, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the virtio-iommu epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/lib.rs b/virtio-devices/src/lib.rs index 35b3b9015..c863616ce 100644 --- a/virtio-devices/src/lib.rs +++ b/virtio-devices/src/lib.rs @@ -32,6 +32,7 @@ pub mod net; mod pmem; mod rng; pub mod seccomp_filters; +mod thread_helper; pub mod transport; pub mod vhost_user; pub mod vsock; diff --git a/virtio-devices/src/mem.rs b/virtio-devices/src/mem.rs index 960566f87..f4522054b 100644 --- a/virtio-devices/src/mem.rs +++ b/virtio-devices/src/mem.rs @@ -18,12 +18,13 @@ use super::{ EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::{GuestMemoryMmap, GuestRegionMmap}; use crate::{VirtioInterrupt, VirtioInterruptType}; use anyhow::anyhow; use libc::EFD_NONBLOCK; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::collections::BTreeMap; use std::io; use std::mem::size_of; @@ -32,7 +33,6 @@ use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::mpsc; use std::sync::{Arc, Barrier, Mutex}; -use std::thread; use vm_device::dma_mapping::ExternalDmaMapping; use vm_memory::{ Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, @@ -955,27 +955,18 @@ impl VirtioDevice for Mem { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_mem thread - let virtio_mem_seccomp_filter = get_seccomp_filter(&self.seccomp_action, Thread::VirtioMem) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_mem_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_mem_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioMem, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone virtio-mem epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); event!("virtio-device", "activated", "id", &self.id); diff --git a/virtio-devices/src/net.rs b/virtio-devices/src/net.rs index b973977ad..07fdf74aa 100644 --- a/virtio-devices/src/net.rs +++ b/virtio-devices/src/net.rs @@ -11,7 +11,8 @@ use super::{ RateLimiterConfig, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; use net_util::CtrlQueue; @@ -20,7 +21,7 @@ use net_util::{ virtio_features_to_tap_offload, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio, Tap, TapError, TxVirtio, VirtioNetConfig, }; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::net::Ipv4Addr; use std::num::Wrapping; use std::os::unix::io::{AsRawFd, RawFd}; @@ -569,28 +570,19 @@ impl VirtioDevice for Net { self.common.paused_sync = Some(Arc::new(Barrier::new(self.taps.len() + 2))); let paused_sync = self.common.paused_sync.clone(); - // Retrieve seccomp filter for virtio_net_ctl thread - let virtio_net_ctl_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioNetCtl) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(format!("{}_ctrl", self.id)) - .spawn(move || { - if !virtio_net_ctl_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_net_ctl_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + let mut epoll_threads = Vec::new(); + spawn_virtio_thread( + &format!("{}_ctrl", &self.id), + &self.seccomp_action, + Thread::VirtioNetCtl, + &mut epoll_threads, + move || { if let Err(e) = ctrl_handler.run_ctrl(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| self.ctrl_queue_epoll_thread = Some(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; + self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0)); } let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into()); @@ -656,28 +648,18 @@ impl VirtioDevice for Net { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); - // Retrieve seccomp filter for virtio_net thread - let virtio_net_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioNet) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(format!("{}_qp{}", self.id.clone(), i)) - .spawn(move || { - if !virtio_net_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_net_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &format!("{}_qp{}", self.id.clone(), i), + &self.seccomp_action, + Thread::VirtioNet, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; } self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/pmem.rs b/virtio-devices/src/pmem.rs index 5bd4c0df3..ef74b296d 100644 --- a/virtio-devices/src/pmem.rs +++ b/virtio-devices/src/pmem.rs @@ -12,10 +12,11 @@ use super::{ EpollHelperHandler, Queue, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::{GuestMemoryMmap, MmapRegion}; use crate::{VirtioInterrupt, VirtioInterruptType}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::fmt::{self, Display}; use std::fs::File; use std::io; @@ -24,7 +25,6 @@ use std::os::unix::io::AsRawFd; use std::result; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Barrier}; -use std::thread; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; use vm_memory::{ @@ -390,28 +390,18 @@ impl VirtioDevice for Pmem { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_pmem thread - let virtio_pmem_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioPmem) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_pmem_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_pmem_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioPmem, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone virtio-pmem epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/rng.rs b/virtio-devices/src/rng.rs index 0b89af4c6..2b0157231 100644 --- a/virtio-devices/src/rng.rs +++ b/virtio-devices/src/rng.rs @@ -8,17 +8,17 @@ use super::{ VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{VirtioInterrupt, VirtioInterruptType}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::fs::File; use std::io; use std::os::unix::io::AsRawFd; use std::result; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Barrier}; -use std::thread; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; use vm_memory::{Bytes, GuestAddressSpace, GuestMemoryAtomic}; @@ -236,28 +236,17 @@ impl VirtioDevice for Rng { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_rng thread - let virtio_rng_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioRng) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_rng_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_rng_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioRng, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the virtio-rng epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs index fef6bdabf..20939c237 100644 --- a/virtio-devices/src/seccomp_filters.rs +++ b/virtio-devices/src/seccomp_filters.rs @@ -20,7 +20,9 @@ pub enum Thread { VirtioNetCtl, VirtioPmem, VirtioRng, + VirtioVhostBlock, VirtioVhostFs, + VirtioVhostNet, VirtioVhostNetCtl, VirtioVsock, VirtioWatchdog, @@ -372,6 +374,65 @@ fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec)> { ] } +fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec)> { + vec![ + (libc::SYS_accept4, vec![]), + (libc::SYS_bind, vec![]), + (libc::SYS_brk, vec![]), + #[cfg(feature = "mshv")] + (libc::SYS_clock_gettime, vec![]), + (libc::SYS_close, vec![]), + (libc::SYS_dup, vec![]), + (libc::SYS_epoll_create1, vec![]), + (libc::SYS_epoll_ctl, vec![]), + (libc::SYS_epoll_pwait, vec![]), + #[cfg(target_arch = "x86_64")] + (libc::SYS_epoll_wait, vec![]), + (libc::SYS_exit, vec![]), + (libc::SYS_futex, vec![]), + (libc::SYS_getcwd, vec![]), + (libc::SYS_listen, vec![]), + (libc::SYS_munmap, vec![]), + (libc::SYS_madvise, vec![]), + (libc::SYS_read, vec![]), + (libc::SYS_recvmsg, vec![]), + (libc::SYS_rt_sigprocmask, vec![]), + (libc::SYS_rt_sigreturn, vec![]), + (libc::SYS_sendmsg, vec![]), + (libc::SYS_sendto, vec![]), + (libc::SYS_sigaltstack, vec![]), + (libc::SYS_socket, vec![]), + #[cfg(target_arch = "x86_64")] + (libc::SYS_unlink, vec![]), + #[cfg(target_arch = "aarch64")] + (libc::SYS_unlinkat, vec![]), + (libc::SYS_write, vec![]), + ] +} + +fn virtio_vhost_block_thread_rules() -> Vec<(i64, Vec)> { + vec![ + (libc::SYS_brk, vec![]), + #[cfg(feature = "mshv")] + (libc::SYS_clock_gettime, vec![]), + (libc::SYS_close, vec![]), + (libc::SYS_dup, vec![]), + (libc::SYS_epoll_create1, vec![]), + (libc::SYS_epoll_ctl, vec![]), + (libc::SYS_epoll_pwait, vec![]), + #[cfg(target_arch = "x86_64")] + (libc::SYS_epoll_wait, vec![]), + (libc::SYS_exit, vec![]), + (libc::SYS_futex, vec![]), + (libc::SYS_munmap, vec![]), + (libc::SYS_madvise, vec![]), + (libc::SYS_read, vec![]), + (libc::SYS_rt_sigprocmask, vec![]), + (libc::SYS_sigaltstack, vec![]), + (libc::SYS_write, vec![]), + ] +} + fn create_vsock_ioctl_seccomp_rule() -> Vec { or![and![Cond::new(1, ArgLen::Dword, Eq, FIONBIO,).unwrap()],] } @@ -445,7 +506,9 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec)> { Thread::VirtioNetCtl => virtio_net_ctl_thread_rules(), Thread::VirtioPmem => virtio_pmem_thread_rules(), Thread::VirtioRng => virtio_rng_thread_rules(), + Thread::VirtioVhostBlock => virtio_vhost_block_thread_rules(), Thread::VirtioVhostFs => virtio_vhost_fs_thread_rules(), + Thread::VirtioVhostNet => virtio_vhost_net_thread_rules(), Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(), Thread::VirtioVsock => virtio_vsock_thread_rules(), Thread::VirtioWatchdog => virtio_watchdog_thread_rules(), diff --git a/virtio-devices/src/thread_helper.rs b/virtio-devices/src/thread_helper.rs new file mode 100644 index 000000000..b145c7e69 --- /dev/null +++ b/virtio-devices/src/thread_helper.rs @@ -0,0 +1,43 @@ +// Copyright © 2021 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::{ + seccomp_filters::{get_seccomp_filter, Thread}, + ActivateError, +}; +use seccompiler::{apply_filter, SeccompAction}; +use std::thread::{self, JoinHandle}; + +pub(crate) fn spawn_virtio_thread( + name: &str, + seccomp_action: &SeccompAction, + thread_type: Thread, + epoll_threads: &mut Vec>, + f: F, +) -> Result<(), ActivateError> +where + F: FnOnce(), + F: Send + 'static, +{ + let seccomp_filter = get_seccomp_filter(seccomp_action, thread_type) + .map_err(ActivateError::CreateSeccompFilter)?; + + thread::Builder::new() + .name(name.to_string()) + .spawn(move || { + if !seccomp_filter.is_empty() { + if let Err(e) = apply_filter(&seccomp_filter) { + error!("Error applying seccomp filter: {:?}", e); + return; + } + } + f() + }) + .map(|thread| epoll_threads.push(thread)) + .map_err(|e| { + error!("Failed to spawn thread for {}: {}", name, e); + ActivateError::BadActivate + }) +} diff --git a/virtio-devices/src/vhost_user/blk.rs b/virtio-devices/src/vhost_user/blk.rs index 6058cebfd..4d8dac2ac 100644 --- a/virtio-devices/src/vhost_user/blk.rs +++ b/virtio-devices/src/vhost_user/blk.rs @@ -1,15 +1,16 @@ // Copyright 2019 Intel Corporation. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -use super::super::{ - ActivateError, ActivateResult, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, -}; +use super::super::{ActivateResult, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType}; use super::vu_common_ctrl::{VhostUserConfig, VhostUserHandle}; use super::{Error, Result, DEFAULT_VIRTIO_FEATURES}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::vhost_user::VhostUserCommon; use crate::VirtioInterrupt; use crate::{GuestMemoryMmap, GuestRegionMmap}; use block_util::VirtioBlockConfig; +use seccompiler::SeccompAction; use std::mem; use std::result; use std::sync::{Arc, Barrier, Mutex}; @@ -57,11 +58,17 @@ pub struct Blk { config: VirtioBlockConfig, guest_memory: Option>, epoll_thread: Option>, + seccomp_action: SeccompAction, } impl Blk { /// Create a new vhost-user-blk device - pub fn new(id: String, vu_cfg: VhostUserConfig, restoring: bool) -> Result { + pub fn new( + id: String, + vu_cfg: VhostUserConfig, + restoring: bool, + seccomp_action: SeccompAction, + ) -> Result { let num_queues = vu_cfg.num_queues; if restoring { @@ -85,6 +92,7 @@ impl Blk { config: VirtioBlockConfig::default(), guest_memory: None, epoll_thread: None, + seccomp_action, }); } @@ -171,6 +179,7 @@ impl Blk { config, guest_memory: None, epoll_thread: None, + seccomp_action, }) } @@ -298,18 +307,20 @@ impl VirtioDevice for Blk { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); - thread::Builder::new() - .name(self.id.to_string()) - .spawn(move || { + let mut epoll_threads = Vec::new(); + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioVhostBlock, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { - error!("Error running vhost-user-blk worker: {:?}", e); + error!("Error running worker: {:?}", e); } - }) - .map(|thread| self.epoll_thread = Some(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; + self.epoll_thread = Some(epoll_threads.remove(0)); Ok(()) } diff --git a/virtio-devices/src/vhost_user/fs.rs b/virtio-devices/src/vhost_user/fs.rs index f2e3d4c8c..cb8aa570d 100644 --- a/virtio-devices/src/vhost_user/fs.rs +++ b/virtio-devices/src/vhost_user/fs.rs @@ -3,7 +3,8 @@ use super::vu_common_ctrl::VhostUserHandle; use super::{Error, Result, DEFAULT_VIRTIO_FEATURES}; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::vhost_user::VhostUserCommon; use crate::{ ActivateError, ActivateResult, Queue, UserspaceMapping, VirtioCommon, VirtioDevice, @@ -11,7 +12,7 @@ use crate::{ }; use crate::{GuestMemoryMmap, GuestRegionMmap, MmapRegion}; use libc::{self, c_void, off64_t, pread64, pwrite64}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::io; use std::os::unix::io::AsRawFd; use std::result; @@ -549,28 +550,19 @@ impl VirtioDevice for Fs { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); - let virtio_vhost_fs_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioVhostFs) - .map_err(ActivateError::CreateSeccompFilter)?; - - thread::Builder::new() - .name(self.id.to_string()) - .spawn(move || { - if !virtio_vhost_fs_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_vhost_fs_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + let mut epoll_threads = Vec::new(); + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioVhostFs, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { - error!("Error running vhost-user-fs worker: {:?}", e); + error!("Error running worker: {:?}", e); } - }) - .map(|thread| self.epoll_thread = Some(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; + self.epoll_thread = Some(epoll_threads.remove(0)); event!("virtio-device", "activated", "id", &self.id); Ok(()) diff --git a/virtio-devices/src/vhost_user/net.rs b/virtio-devices/src/vhost_user/net.rs index 9313e1e5d..c587ef9b5 100644 --- a/virtio-devices/src/vhost_user/net.rs +++ b/virtio-devices/src/vhost_user/net.rs @@ -1,17 +1,18 @@ // Copyright 2019 Intel Corporation. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::vhost_user::vu_common_ctrl::{VhostUserConfig, VhostUserHandle}; use crate::vhost_user::{Error, Result, VhostUserCommon}; use crate::{ - ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, - VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST, + ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon, + VirtioDevice, VirtioDeviceType, VirtioInterrupt, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1, }; use crate::{GuestMemoryMmap, GuestRegionMmap}; use net_util::{build_net_config_space, CtrlQueue, MacAddr, VirtioNetConfig}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::os::unix::io::AsRawFd; use std::result; use std::sync::atomic::AtomicBool; @@ -332,28 +333,19 @@ impl VirtioDevice for Net { self.common.paused_sync = Some(Arc::new(Barrier::new(3))); let paused_sync = self.common.paused_sync.clone(); - // Retrieve seccomp filter for virtio_net_ctl thread - let virtio_vhost_net_ctl_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioVhostNetCtl) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(format!("{}_ctrl", self.id)) - .spawn(move || { - if !virtio_vhost_net_ctl_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_vhost_net_ctl_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + let mut epoll_threads = Vec::new(); + spawn_virtio_thread( + &format!("{}_ctrl", &self.id), + &self.seccomp_action, + Thread::VirtioVhostNetCtl, + &mut epoll_threads, + move || { if let Err(e) = ctrl_handler.run_ctrl(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| self.ctrl_queue_epoll_thread = Some(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; + self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0)); } let slave_req_handler: Option> = None; @@ -383,18 +375,19 @@ impl VirtioDevice for Net { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); - thread::Builder::new() - .name(self.id.to_string()) - .spawn(move || { + let mut epoll_threads = Vec::new(); + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioVhostNet, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { - error!("Error running vhost-user-net worker: {:?}", e); + error!("Error running worker: {:?}", e); } - }) - .map(|thread| self.epoll_thread = Some(thread)) - .map_err(|e| { - error!("failed to clone queue EventFd: {}", e); - ActivateError::BadActivate - })?; + }, + )?; + self.epoll_thread = Some(epoll_threads.remove(0)); Ok(()) } diff --git a/virtio-devices/src/vsock/device.rs b/virtio-devices/src/vsock/device.rs index 53ac0a1d4..2ebce885e 100644 --- a/virtio-devices/src/vsock/device.rs +++ b/virtio-devices/src/vsock/device.rs @@ -28,24 +28,23 @@ /// - a backend FD. /// use super::{VsockBackend, VsockPacket}; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; use crate::Error as DeviceError; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; use crate::{ - ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, - VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST, - VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, + thread_helper::spawn_virtio_thread, ActivateResult, EpollHelper, EpollHelperError, + EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType, + EPOLL_HELPER_EVENT_LAST, VIRTIO_F_IN_ORDER, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_VERSION_1, }; use byteorder::{ByteOrder, LittleEndian}; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::io; use std::os::unix::io::AsRawFd; use std::path::PathBuf; use std::result; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Barrier, RwLock}; -use std::thread; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; use vm_memory::{GuestAddressSpace, GuestMemoryAtomic}; @@ -434,28 +433,18 @@ where let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_vsock thread - let virtio_vsock_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioVsock) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_vsock_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_vsock_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioVsock, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the vsock epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); @@ -513,6 +502,7 @@ mod tests { use super::super::*; use super::*; use crate::vsock::device::{BACKEND_EVENT, EVT_QUEUE_EVENT, RX_QUEUE_EVENT, TX_QUEUE_EVENT}; + use crate::ActivateError; use libc::EFD_NONBLOCK; #[test] diff --git a/virtio-devices/src/watchdog.rs b/virtio-devices/src/watchdog.rs index b23bfe53b..2de412535 100644 --- a/virtio-devices/src/watchdog.rs +++ b/virtio-devices/src/watchdog.rs @@ -10,18 +10,18 @@ use super::{ ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, }; -use crate::seccomp_filters::{get_seccomp_filter, Thread}; +use crate::seccomp_filters::Thread; +use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::{VirtioInterrupt, VirtioInterruptType}; use anyhow::anyhow; -use seccompiler::{apply_filter, SeccompAction}; +use seccompiler::SeccompAction; use std::fs::File; use std::io::{self, Read}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::result; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Barrier, Mutex}; -use std::thread; use std::time::Instant; use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize_derive::Versionize; @@ -318,29 +318,18 @@ impl VirtioDevice for Watchdog { let paused = self.common.paused.clone(); let paused_sync = self.common.paused_sync.clone(); let mut epoll_threads = Vec::new(); - // Retrieve seccomp filter for virtio_watchdog thread - let virtio_watchdog_seccomp_filter = - get_seccomp_filter(&self.seccomp_action, Thread::VirtioWatchdog) - .map_err(ActivateError::CreateSeccompFilter)?; - thread::Builder::new() - .name(self.id.clone()) - .spawn(move || { - if !virtio_watchdog_seccomp_filter.is_empty() { - if let Err(e) = apply_filter(&virtio_watchdog_seccomp_filter) { - error!("Error applying seccomp filter: {:?}", e); - return; - } - } + spawn_virtio_thread( + &self.id, + &self.seccomp_action, + Thread::VirtioWatchdog, + &mut epoll_threads, + move || { if let Err(e) = handler.run(paused, paused_sync.unwrap()) { error!("Error running worker: {:?}", e); } - }) - .map(|thread| epoll_threads.push(thread)) - .map_err(|e| { - error!("failed to clone the virtio-watchdog epoll thread: {}", e); - ActivateError::BadActivate - })?; + }, + )?; self.common.epoll_threads = Some(epoll_threads); diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 7ff0b89c2..f2af64b3d 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -1862,7 +1862,12 @@ impl DeviceManager { queue_size: disk_cfg.queue_size, }; let vhost_user_block_device = Arc::new(Mutex::new( - match virtio_devices::vhost_user::Blk::new(id.clone(), vu_cfg, self.restoring) { + match virtio_devices::vhost_user::Blk::new( + id.clone(), + vu_cfg, + self.restoring, + self.seccomp_action.clone(), + ) { Ok(vub_device) => vub_device, Err(e) => { return Err(DeviceManagerError::CreateVhostUserBlk(e));