mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: seccomp: Add seccomp_filter module
This patch added the seccomp_filter module to the virtio-devices crate by taking reference code from the vmm crate. This patch also adds allowed-list for the virtio-block worker thread. Partially fixes: #925 Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
@@ -13,7 +13,7 @@ io_uring = ["block_util/io_uring"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
arc-swap = ">=0.4.4"
|
arc-swap = ">=0.4.4"
|
||||||
block_util = { path = "../block_util" }
|
block_util = { path = "../block_util" }
|
||||||
byteorder = "1.3.4"
|
byteorder = "1.3.4"
|
||||||
devices = { path = "../devices" }
|
devices = { path = "../devices" }
|
||||||
epoll = ">=4.0.1"
|
epoll = ">=4.0.1"
|
||||||
@@ -23,6 +23,7 @@ log = "0.4.11"
|
|||||||
net_gen = { path = "../net_gen" }
|
net_gen = { path = "../net_gen" }
|
||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
pci = { path = "../pci", optional = true }
|
pci = { path = "../pci", optional = true }
|
||||||
|
seccomp = { git = "https://github.com/firecracker-microvm/firecracker", tag = "v0.21.1" }
|
||||||
serde = ">=1.0.27"
|
serde = ">=1.0.27"
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = ">=1.0.27"
|
||||||
serde_json = ">=1.0.9"
|
serde_json = ">=1.0.9"
|
||||||
@@ -36,4 +37,3 @@ vm-memory = { version = "0.2.1", features = ["backend-mmap", "backend-atomic"] }
|
|||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ use super::{
|
|||||||
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
|
||||||
VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST,
|
VirtioDevice, VirtioDeviceType, VirtioInterruptType, EPOLL_HELPER_EVENT_LAST,
|
||||||
};
|
};
|
||||||
|
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||||
use crate::VirtioInterrupt;
|
use crate::VirtioInterrupt;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use block_util::{build_disk_image_id, Request, RequestType, VirtioBlockConfig};
|
use block_util::{build_disk_image_id, Request, RequestType, VirtioBlockConfig};
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
|
use seccomp::{SeccompAction, SeccompFilter};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
@@ -268,6 +270,7 @@ pub struct Block<T: DiskFile> {
|
|||||||
queue_size: Vec<u16>,
|
queue_size: Vec<u16>,
|
||||||
writeback: Arc<AtomicBool>,
|
writeback: Arc<AtomicBool>,
|
||||||
counters: BlockCounters,
|
counters: BlockCounters,
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -283,6 +286,7 @@ impl<T: DiskFile> Block<T> {
|
|||||||
/// Create a new virtio block device that operates on the given file.
|
/// Create a new virtio block device that operates on the given file.
|
||||||
///
|
///
|
||||||
/// The given file must be seekable and sizable.
|
/// The given file must be seekable and sizable.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: String,
|
id: String,
|
||||||
mut disk_image: T,
|
mut disk_image: T,
|
||||||
@@ -291,6 +295,7 @@ impl<T: DiskFile> Block<T> {
|
|||||||
iommu: bool,
|
iommu: bool,
|
||||||
num_queues: usize,
|
num_queues: usize,
|
||||||
queue_size: u16,
|
queue_size: u16,
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
) -> io::Result<Block<T>> {
|
) -> io::Result<Block<T>> {
|
||||||
let disk_size = disk_image.seek(SeekFrom::End(0))? as u64;
|
let disk_size = disk_image.seek(SeekFrom::End(0))? as u64;
|
||||||
if disk_size % SECTOR_SIZE != 0 {
|
if disk_size % SECTOR_SIZE != 0 {
|
||||||
@@ -343,6 +348,7 @@ impl<T: DiskFile> Block<T> {
|
|||||||
queue_size: vec![queue_size; num_queues],
|
queue_size: vec![queue_size; num_queues],
|
||||||
writeback: Arc::new(AtomicBool::new(true)),
|
writeback: Arc::new(AtomicBool::new(true)),
|
||||||
counters: BlockCounters::default(),
|
counters: BlockCounters::default(),
|
||||||
|
seccomp_action,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,9 +533,19 @@ impl<T: 'static + DiskFile + Send> VirtioDevice for Block<T> {
|
|||||||
handler.queue.set_event_idx(event_idx);
|
handler.queue.set_event_idx(event_idx);
|
||||||
|
|
||||||
let paused = self.paused.clone();
|
let paused = self.paused.clone();
|
||||||
|
|
||||||
|
// Retrieve seccomp filter for virtio_blk thread
|
||||||
|
let api_seccomp_filter = get_seccomp_filter(&self.seccomp_action, Thread::VirtioBlk)
|
||||||
|
.map_err(ActivateError::CreateSeccompFilter)?;
|
||||||
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("virtio_blk".to_string())
|
.name("virtio_blk".to_string())
|
||||||
.spawn(move || handler.run(paused))
|
.spawn(move || {
|
||||||
|
SeccompFilter::apply(api_seccomp_filter)
|
||||||
|
.map_err(EpollHelperError::ApplySeccompFilter)?;
|
||||||
|
|
||||||
|
handler.run(paused)
|
||||||
|
})
|
||||||
.map(|thread| epoll_threads.push(thread))
|
.map(|thread| epoll_threads.push(thread))
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("failed to clone the virtio-blk epoll thread: {}", e);
|
error!("failed to clone the virtio-blk epoll thread: {}", e);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub enum EpollHelperError {
|
|||||||
CreateFd(std::io::Error),
|
CreateFd(std::io::Error),
|
||||||
Ctl(std::io::Error),
|
Ctl(std::io::Error),
|
||||||
Wait(std::io::Error),
|
Wait(std::io::Error),
|
||||||
|
ApplySeccompFilter(seccomp::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const EPOLL_HELPER_EVENT_PAUSE: u16 = 0;
|
pub const EPOLL_HELPER_EVENT_PAUSE: u16 = 0;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ pub mod net;
|
|||||||
pub mod net_util;
|
pub mod net_util;
|
||||||
mod pmem;
|
mod pmem;
|
||||||
mod rng;
|
mod rng;
|
||||||
|
pub mod seccomp_filters;
|
||||||
pub mod transport;
|
pub mod transport;
|
||||||
pub mod vhost_user;
|
pub mod vhost_user;
|
||||||
pub mod vsock;
|
pub mod vsock;
|
||||||
@@ -97,6 +98,8 @@ pub enum ActivateError {
|
|||||||
VhostUserBlkSetup(vhost_user::Error),
|
VhostUserBlkSetup(vhost_user::Error),
|
||||||
/// Failed to reset vhost-user daemon.
|
/// Failed to reset vhost-user daemon.
|
||||||
VhostUserReset(vhost_user::Error),
|
VhostUserReset(vhost_user::Error),
|
||||||
|
/// Cannot create seccomp filter
|
||||||
|
CreateSeccompFilter(seccomp::SeccompError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ActivateResult = std::result::Result<(), ActivateError>;
|
pub type ActivateResult = std::result::Result<(), ActivateError>;
|
||||||
|
|||||||
91
virtio-devices/src/seccomp_filters.rs
Normal file
91
virtio-devices/src/seccomp_filters.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Copyright © 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use seccomp::{
|
||||||
|
allow_syscall, BpfProgram, Error, SeccompAction, SeccompError, SeccompFilter, SyscallRuleSet,
|
||||||
|
};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
pub enum Thread {
|
||||||
|
VirtioBlk,
|
||||||
|
}
|
||||||
|
|
||||||
|
// The filter containing the allowed syscall rules required by the
|
||||||
|
// virtio_blk thread to function.
|
||||||
|
fn virtio_blk_thread_rules() -> Result<Vec<SyscallRuleSet>, Error> {
|
||||||
|
Ok(vec![
|
||||||
|
allow_syscall(libc::SYS_brk),
|
||||||
|
allow_syscall(libc::SYS_close),
|
||||||
|
allow_syscall(libc::SYS_dup),
|
||||||
|
allow_syscall(libc::SYS_epoll_create1),
|
||||||
|
allow_syscall(libc::SYS_epoll_ctl),
|
||||||
|
allow_syscall(libc::SYS_epoll_pwait),
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
allow_syscall(libc::SYS_epoll_wait),
|
||||||
|
allow_syscall(libc::SYS_exit),
|
||||||
|
allow_syscall(libc::SYS_fallocate),
|
||||||
|
allow_syscall(libc::SYS_fdatasync),
|
||||||
|
allow_syscall(libc::SYS_fsync),
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
allow_syscall(libc::SYS_ftruncate),
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
// The definition of libc::SYS_ftruncate is missing on AArch64.
|
||||||
|
// Use a hard-code number instead.
|
||||||
|
allow_syscall(46),
|
||||||
|
allow_syscall(libc::SYS_futex),
|
||||||
|
allow_syscall(libc::SYS_lseek),
|
||||||
|
allow_syscall(libc::SYS_madvise),
|
||||||
|
allow_syscall(libc::SYS_mmap),
|
||||||
|
allow_syscall(libc::SYS_mprotect),
|
||||||
|
allow_syscall(libc::SYS_munmap),
|
||||||
|
allow_syscall(libc::SYS_openat),
|
||||||
|
allow_syscall(libc::SYS_prctl),
|
||||||
|
allow_syscall(libc::SYS_read),
|
||||||
|
allow_syscall(libc::SYS_rt_sigprocmask),
|
||||||
|
allow_syscall(libc::SYS_sched_getaffinity),
|
||||||
|
allow_syscall(libc::SYS_set_robust_list),
|
||||||
|
allow_syscall(libc::SYS_sigaltstack),
|
||||||
|
allow_syscall(libc::SYS_write),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_seccomp_filter_trap(thread_type: Thread) -> Result<SeccompFilter, Error> {
|
||||||
|
let rules = match thread_type {
|
||||||
|
Thread::VirtioBlk => virtio_blk_thread_rules()?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SeccompFilter::new(
|
||||||
|
rules.into_iter().collect(),
|
||||||
|
SeccompAction::Trap,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_seccomp_filter_log(thread_type: Thread) -> Result<SeccompFilter, Error> {
|
||||||
|
let rules = match thread_type {
|
||||||
|
Thread::VirtioBlk => virtio_blk_thread_rules()?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SeccompFilter::new(
|
||||||
|
rules.into_iter().collect(),
|
||||||
|
SeccompAction::Log,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a BPF program based on the seccomp_action value
|
||||||
|
pub fn get_seccomp_filter(
|
||||||
|
seccomp_action: &SeccompAction,
|
||||||
|
thread_type: Thread,
|
||||||
|
) -> Result<BpfProgram, SeccompError> {
|
||||||
|
match seccomp_action {
|
||||||
|
SeccompAction::Allow => Ok(vec![]),
|
||||||
|
SeccompAction::Log => get_seccomp_filter_log(thread_type)
|
||||||
|
.and_then(|filter| filter.try_into())
|
||||||
|
.map_err(SeccompError::SeccompFilter),
|
||||||
|
_ => get_seccomp_filter_trap(thread_type)
|
||||||
|
.and_then(|filter| filter.try_into())
|
||||||
|
.map_err(SeccompError::SeccompFilter),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ use pci::{
|
|||||||
VfioPciDevice,
|
VfioPciDevice,
|
||||||
};
|
};
|
||||||
use qcow::{self, ImageType, QcowFile};
|
use qcow::{self, ImageType, QcowFile};
|
||||||
|
use seccomp::SeccompAction;
|
||||||
#[cfg(feature = "pci_support")]
|
#[cfg(feature = "pci_support")]
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -801,6 +802,9 @@ pub struct DeviceManager {
|
|||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
id_to_dev_info: HashMap<(DeviceType, String), MMIODeviceInfo>,
|
id_to_dev_info: HashMap<(DeviceType, String), MMIODeviceInfo>,
|
||||||
|
|
||||||
|
// seccomp action
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceManager {
|
impl DeviceManager {
|
||||||
@@ -811,6 +815,7 @@ impl DeviceManager {
|
|||||||
_exit_evt: &EventFd,
|
_exit_evt: &EventFd,
|
||||||
#[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd,
|
#[cfg_attr(target_arch = "aarch64", allow(unused_variables))] reset_evt: &EventFd,
|
||||||
vmm_path: PathBuf,
|
vmm_path: PathBuf,
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
) -> DeviceManagerResult<Arc<Mutex<Self>>> {
|
) -> DeviceManagerResult<Arc<Mutex<Self>>> {
|
||||||
let device_tree = Arc::new(Mutex::new(DeviceTree::new()));
|
let device_tree = Arc::new(Mutex::new(DeviceTree::new()));
|
||||||
|
|
||||||
@@ -872,6 +877,7 @@ impl DeviceManager {
|
|||||||
reset_evt: reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
|
reset_evt: reset_evt.try_clone().map_err(DeviceManagerError::EventFd)?,
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
id_to_dev_info: HashMap::new(),
|
id_to_dev_info: HashMap::new(),
|
||||||
|
seccomp_action,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
#[cfg(feature = "acpi")]
|
||||||
@@ -1710,6 +1716,7 @@ impl DeviceManager {
|
|||||||
disk_cfg.iommu,
|
disk_cfg.iommu,
|
||||||
disk_cfg.num_queues,
|
disk_cfg.num_queues,
|
||||||
disk_cfg.queue_size,
|
disk_cfg.queue_size,
|
||||||
|
self.seccomp_action.clone(),
|
||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
||||||
));
|
));
|
||||||
@@ -1736,6 +1743,7 @@ impl DeviceManager {
|
|||||||
disk_cfg.iommu,
|
disk_cfg.iommu,
|
||||||
disk_cfg.num_queues,
|
disk_cfg.num_queues,
|
||||||
disk_cfg.queue_size,
|
disk_cfg.queue_size,
|
||||||
|
self.seccomp_action.clone(),
|
||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
||||||
));
|
));
|
||||||
@@ -1762,6 +1770,7 @@ impl DeviceManager {
|
|||||||
disk_cfg.iommu,
|
disk_cfg.iommu,
|
||||||
disk_cfg.num_queues,
|
disk_cfg.num_queues,
|
||||||
disk_cfg.queue_size,
|
disk_cfg.queue_size,
|
||||||
|
self.seccomp_action.clone(),
|
||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
.map_err(DeviceManagerError::CreateVirtioBlock)?,
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ impl Vm {
|
|||||||
exit_evt: EventFd,
|
exit_evt: EventFd,
|
||||||
reset_evt: EventFd,
|
reset_evt: EventFd,
|
||||||
vmm_path: PathBuf,
|
vmm_path: PathBuf,
|
||||||
_seccomp_action: &SeccompAction,
|
seccomp_action: &SeccompAction,
|
||||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||||
_saved_clock: Option<hypervisor::ClockData>,
|
_saved_clock: Option<hypervisor::ClockData>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
@@ -285,6 +285,7 @@ impl Vm {
|
|||||||
&exit_evt,
|
&exit_evt,
|
||||||
&reset_evt,
|
&reset_evt,
|
||||||
vmm_path,
|
vmm_path,
|
||||||
|
seccomp_action.clone(),
|
||||||
)
|
)
|
||||||
.map_err(Error::DeviceManager)?;
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user