dragonball: add seccomp support for dragonball

This commit modifies seccomp framework to
support different restrictions for different threads.

Signed-off-by: wangxinge <wangxinge@bupt.edu.cn>
This commit is contained in:
wangxinge
2025-09-29 13:46:09 +08:00
committed by Xuewei Niu
parent bb6fb8ff39
commit 2abf6965ff
7 changed files with 73 additions and 42 deletions

View File

@@ -344,20 +344,26 @@ name = "dbs-pci"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"dbs-address-space",
"dbs-allocator", "dbs-allocator",
"dbs-arch", "dbs-arch",
"dbs-boot", "dbs-boot",
"dbs-device", "dbs-device",
"dbs-interrupt", "dbs-interrupt",
"dbs-utils",
"dbs-virtio-devices",
"downcast-rs", "downcast-rs",
"kvm-bindings", "kvm-bindings",
"kvm-ioctls", "kvm-ioctls",
"libc", "libc",
"log", "log",
"serde",
"thiserror 1.0.48", "thiserror 1.0.48",
"vfio-bindings", "vfio-bindings",
"vfio-ioctls", "vfio-ioctls",
"virtio-queue",
"vm-memory", "vm-memory",
"vmm-sys-util",
] ]
[[package]] [[package]]
@@ -1810,9 +1816,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "seccompiler" name = "seccompiler"
version = "0.2.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01d1292a1131b22ccea49f30bd106f1238b5ddeec1a98d39268dcc31d540e68" checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884"
dependencies = [ dependencies = [
"libc", "libc",
] ]

View File

@@ -33,7 +33,7 @@ event-manager = "0.2.1"
kvm-bindings = "0.6.0" kvm-bindings = "0.6.0"
kvm-ioctls = "0.12.0" kvm-ioctls = "0.12.0"
linux-loader = "0.8.0" linux-loader = "0.8.0"
seccompiler = "0.2.0" seccompiler = "0.5.0"
vfio-bindings = "0.3.0" vfio-bindings = "0.3.0"
vfio-ioctls = "0.1.0" vfio-ioctls = "0.1.0"
virtio-bindings = "0.1.0" virtio-bindings = "0.1.0"

View File

@@ -479,14 +479,13 @@ impl VmmService {
use self::StartMicroVmError::MicroVMAlreadyRunning; use self::StartMicroVmError::MicroVMAlreadyRunning;
use self::VmmActionError::StartMicroVm; use self::VmmActionError::StartMicroVm;
let vmm_seccomp_filter = vmm.vmm_seccomp_filter(); let seccomp_filters = vmm.seccomp_filters();
let vcpu_seccomp_filter = vmm.vcpu_seccomp_filter();
let vm = vmm.get_vm_mut().ok_or(VmmActionError::InvalidVMID)?; let vm = vmm.get_vm_mut().ok_or(VmmActionError::InvalidVMID)?;
if vm.is_vm_initialized() { if vm.is_vm_initialized() {
return Err(StartMicroVm(MicroVMAlreadyRunning)); return Err(StartMicroVm(MicroVMAlreadyRunning));
} }
vm.start_microvm(event_mgr, vmm_seccomp_filter, vcpu_seccomp_filter) vm.start_microvm(event_mgr, seccomp_filters)
.map(|_| VmmData::Empty) .map(|_| VmmData::Empty)
.map_err(StartMicroVm) .map_err(StartMicroVm)
} }

View File

@@ -219,6 +219,10 @@ pub enum StartMicroVmError {
/// Failed to register DMA memory address range. /// Failed to register DMA memory address range.
#[error("failure while registering DMA address range: {0:?}")] #[error("failure while registering DMA address range: {0:?}")]
RegisterDMAAddress(#[source] VfioDeviceError), RegisterDMAAddress(#[source] VfioDeviceError),
/// Cannot build seccomp filters.
#[error("failure while configuring seccomp filters: {0}")]
SeccompFilters(#[source] seccompiler::Error),
} }
/// Errors associated with starting the instance. /// Errors associated with starting the instance.

View File

@@ -48,7 +48,7 @@ mod vmm;
pub use self::error::StartMicroVmError; pub use self::error::StartMicroVmError;
pub use self::io_manager::IoManagerCached; pub use self::io_manager::IoManagerCached;
pub use self::vmm::Vmm; pub use self::vmm::{Vmm, ALL_THREADS, VCPU_THREAD, VMM_THREAD};
/// Success exit code. /// Success exit code.
pub const EXIT_CODE_OK: u8 = 0; pub const EXIT_CODE_OK: u8 = 0;

View File

@@ -1,6 +1,7 @@
// Copyright (C) 2021 Alibaba Cloud. All rights reserved. // Copyright (C) 2021 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::collections::HashMap;
use std::io::{self, Read, Seek, SeekFrom}; use std::io::{self, Read, Seek, SeekFrom};
use std::ops::Deref; use std::ops::Deref;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
@@ -18,6 +19,7 @@ use dbs_utils::time::TimestampUs;
use kvm_ioctls::VmFd; use kvm_ioctls::VmFd;
use linux_loader::loader::{KernelLoader, KernelLoaderResult}; use linux_loader::loader::{KernelLoader, KernelLoaderResult};
use seccompiler::BpfProgram; use seccompiler::BpfProgram;
use seccompiler::{apply_filter_all_threads, Error as SecError};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use slog::{error, info}; use slog::{error, info};
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace}; use vm_memory::{Bytes, GuestAddress, GuestAddressSpace};
@@ -42,6 +44,7 @@ use crate::resource_manager::ResourceManager;
use crate::vcpu::{VcpuManager, VcpuManagerError}; use crate::vcpu::{VcpuManager, VcpuManagerError};
#[cfg(feature = "hotplug")] #[cfg(feature = "hotplug")]
use crate::vcpu::{VcpuResizeError, VcpuResizeInfo}; use crate::vcpu::{VcpuResizeError, VcpuResizeInfo};
use crate::{ALL_THREADS, VCPU_THREAD, VMM_THREAD};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use dbs_arch::gic::Error as GICError; use dbs_arch::gic::Error as GICError;
@@ -709,10 +712,27 @@ impl Vm {
pub fn start_microvm( pub fn start_microvm(
&mut self, &mut self,
event_mgr: &mut EventManager, event_mgr: &mut EventManager,
vmm_seccomp_filter: BpfProgram, seccomp_filters: HashMap<String, BpfProgram>,
vcpu_seccomp_filter: BpfProgram,
) -> std::result::Result<(), StartMicroVmError> { ) -> std::result::Result<(), StartMicroVmError> {
info!(self.logger, "VM: received instance start command"); info!(self.logger, "VM: received instance start command");
if let Some(process_seccomp_filter) = seccomp_filters.get(ALL_THREADS) {
// Load seccomp filters for the whole process.
// Execution panics if filters cannot be loaded, use --seccomp-level=0 if skipping filters
// altogether is the desired behaviour.
if let Err(e) = apply_filter_all_threads(process_seccomp_filter) {
if !matches!(e, SecError::EmptyFilter) {
error!(
self.logger,
"VM: failed to apply process-wide seccomp filters: {}", e
);
return Err(StartMicroVmError::SeccompFilters(e));
}
} else {
info!(self.logger, "VM: process-wide seccomp filters applied");
}
}
if self.is_vm_initialized() { if self.is_vm_initialized() {
return Err(StartMicroVmError::MicroVMAlreadyRunning); return Err(StartMicroVmError::MicroVMAlreadyRunning);
} }
@@ -738,8 +758,14 @@ impl Vm {
AddressManagerError::GuestMemoryNotInitialized, AddressManagerError::GuestMemoryNotInitialized,
))?; ))?;
self.init_vcpu_manager(vm_as.clone(), vcpu_seccomp_filter) self.init_vcpu_manager(
.map_err(StartMicroVmError::Vcpu)?; vm_as.clone(),
seccomp_filters
.get(VCPU_THREAD)
.cloned()
.unwrap_or_default(),
)
.map_err(StartMicroVmError::Vcpu)?;
self.init_microvm(event_mgr.epoll_manager(), vm_as.clone(), request_ts)?; self.init_microvm(event_mgr.epoll_manager(), vm_as.clone(), request_ts)?;
self.init_configure_system(&vm_as)?; self.init_configure_system(&vm_as)?;
#[cfg(feature = "dbs-upcall")] #[cfg(feature = "dbs-upcall")]
@@ -751,7 +777,7 @@ impl Vm {
info!(self.logger, "VM: start vcpus"); info!(self.logger, "VM: start vcpus");
self.vcpu_manager() self.vcpu_manager()
.map_err(StartMicroVmError::Vcpu)? .map_err(StartMicroVmError::Vcpu)?
.start_boot_vcpus(vmm_seccomp_filter) .start_boot_vcpus(seccomp_filters.get(VMM_THREAD).cloned().unwrap_or_default())
.map_err(StartMicroVmError::Vcpu)?; .map_err(StartMicroVmError::Vcpu)?;
// Use expect() to crash if the other thread poisoned this lock. // Use expect() to crash if the other thread poisoned this lock.

View File

@@ -6,6 +6,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file. // found in the THIRD-PARTY file.
use std::collections::HashMap;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
@@ -22,6 +23,19 @@ use crate::event_manager::{EventContext, EventManager};
use crate::vm::Vm; use crate::vm::Vm;
use crate::{EXIT_CODE_GENERIC_ERROR, EXIT_CODE_OK}; use crate::{EXIT_CODE_GENERIC_ERROR, EXIT_CODE_OK};
// Thread types to which the seccomp restrictions apply
// Currently the restrictions are applied to the whole process
// More thread types can be added later to accommodate more granular constraints.
/// Union of restrictions for all threads;
/// The corresponding restrictions are applied to the whole process
/// This type should be used with any other thread type which has specific restrictions
pub const ALL_THREADS: &str = "all";
/// VMM thread
pub const VMM_THREAD: &str = "vmm";
/// Vcpu thread
pub const VCPU_THREAD: &str = "vcpu";
/// Global coordinator to manage API servers, virtual machines, upgrade etc. /// Global coordinator to manage API servers, virtual machines, upgrade etc.
/// ///
/// Originally firecracker assumes an VMM only manages an VM, and doesn't distinguish VMM and VM. /// Originally firecracker assumes an VMM only manages an VM, and doesn't distinguish VMM and VM.
@@ -41,8 +55,7 @@ pub struct Vmm {
// Will change to a HashMap when enabling 1 VMM with multiple VMs. // Will change to a HashMap when enabling 1 VMM with multiple VMs.
vm: Vm, vm: Vm,
vcpu_seccomp_filter: BpfProgram, seccomp_filters: HashMap<String, BpfProgram>,
vmm_seccomp_filter: BpfProgram,
} }
impl Vmm { impl Vmm {
@@ -50,8 +63,7 @@ impl Vmm {
pub fn new( pub fn new(
api_shared_info: Arc<RwLock<InstanceInfo>>, api_shared_info: Arc<RwLock<InstanceInfo>>,
api_event_fd: EventFd, api_event_fd: EventFd,
vmm_seccomp_filter: BpfProgram, seccomp_filters: HashMap<String, BpfProgram>,
vcpu_seccomp_filter: BpfProgram,
kvm_fd: Option<RawFd>, kvm_fd: Option<RawFd>,
) -> Result<Self> { ) -> Result<Self> {
let epoll_manager = EpollManager::default(); let epoll_manager = EpollManager::default();
@@ -59,8 +71,7 @@ impl Vmm {
api_shared_info, api_shared_info,
api_event_fd, api_event_fd,
epoll_manager, epoll_manager,
vmm_seccomp_filter, seccomp_filters,
vcpu_seccomp_filter,
kvm_fd, kvm_fd,
) )
} }
@@ -70,8 +81,7 @@ impl Vmm {
api_shared_info: Arc<RwLock<InstanceInfo>>, api_shared_info: Arc<RwLock<InstanceInfo>>,
api_event_fd: EventFd, api_event_fd: EventFd,
epoll_manager: EpollManager, epoll_manager: EpollManager,
vmm_seccomp_filter: BpfProgram, seccomp_filters: HashMap<String, BpfProgram>,
vcpu_seccomp_filter: BpfProgram,
kvm_fd: Option<RawFd>, kvm_fd: Option<RawFd>,
) -> Result<Self> { ) -> Result<Self> {
let vm = Vm::new(kvm_fd, api_shared_info, epoll_manager.clone())?; let vm = Vm::new(kvm_fd, api_shared_info, epoll_manager.clone())?;
@@ -81,8 +91,7 @@ impl Vmm {
event_ctx, event_ctx,
epoll_manager, epoll_manager,
vm, vm,
vcpu_seccomp_filter, seccomp_filters,
vmm_seccomp_filter,
}) })
} }
@@ -96,14 +105,9 @@ impl Vmm {
Some(&mut self.vm) Some(&mut self.vm)
} }
/// Get the seccomp rules for vCPU threads. /// Get all seccomp rules.
pub fn vcpu_seccomp_filter(&self) -> BpfProgram { pub fn seccomp_filters(&self) -> HashMap<String, BpfProgram> {
self.vcpu_seccomp_filter.clone() self.seccomp_filters.clone()
}
/// Get the seccomp rules for VMM threads.
pub fn vmm_seccomp_filter(&self) -> BpfProgram {
self.vmm_seccomp_filter.clone()
} }
/// Run the event loop to service API requests. /// Run the event loop to service API requests.
@@ -206,14 +210,15 @@ impl std::fmt::Debug for Vmm {
f.debug_struct("Vmm") f.debug_struct("Vmm")
.field("event_ctx", &self.event_ctx) .field("event_ctx", &self.event_ctx)
.field("vm", &self.vm.shared_info()) .field("vm", &self.vm.shared_info())
.field("vcpu_seccomp_filter", &self.vcpu_seccomp_filter) .field("seccomp_filters", &self.seccomp_filters)
.field("vmm_seccomp_filter", &self.vmm_seccomp_filter)
.finish() .finish()
} }
} }
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests { pub(crate) mod tests {
use std::collections::HashMap;
use test_utils::skip_if_not_root; use test_utils::skip_if_not_root;
use super::*; use super::*;
@@ -221,17 +226,8 @@ pub(crate) mod tests {
pub fn create_vmm_instance(epoll_manager: EpollManager) -> Vmm { pub fn create_vmm_instance(epoll_manager: EpollManager) -> Vmm {
let info = Arc::new(RwLock::new(InstanceInfo::default())); let info = Arc::new(RwLock::new(InstanceInfo::default()));
let event_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); let event_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap();
let seccomp_filter: BpfProgram = Vec::new();
Vmm::new_with_epoll_manager( Vmm::new_with_epoll_manager(info, event_fd, epoll_manager, HashMap::new(), None).unwrap()
info,
event_fd,
epoll_manager,
seccomp_filter.clone(),
seccomp_filter,
None,
)
.unwrap()
} }
#[test] #[test]