cloud-hypervisor/virtio-devices/src/seccomp_filters.rs
Rob Bradford 43365ade2e vmm, pci: Implement virtio-mem support for vfio-user
Implement the infrastructure that lets a virtio-mem device map the guest
memory into the device. This is necessary since with virtio-mem zones
memory can be added or removed and the vfio-user device must be
informed.

Fixes: #3025

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2021-09-21 15:42:49 +01:00

293 lines
9.2 KiB
Rust

// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Copyright © 2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
use seccompiler::{
BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen, SeccompCmpOp::Eq,
SeccompCondition as Cond, SeccompFilter, SeccompRule,
};
use std::convert::TryInto;
pub enum Thread {
VirtioBalloon,
VirtioBlock,
VirtioConsole,
VirtioIommu,
VirtioMem,
VirtioNet,
VirtioNetCtl,
VirtioPmem,
VirtioRng,
VirtioVhostBlock,
VirtioVhostFs,
VirtioVhostNet,
VirtioVhostNetCtl,
VirtioVsock,
VirtioWatchdog,
}
/// Shorthand for chaining `SeccompCondition`s with the `and` operator in a `SeccompRule`.
/// The rule will take the `Allow` action if _all_ the conditions are true.
///
/// [`SeccompCondition`]: struct.SeccompCondition.html
/// [`SeccompRule`]: struct.SeccompRule.html
macro_rules! and {
($($x:expr,)*) => (SeccompRule::new(vec![$($x),*]).unwrap());
($($x:expr),*) => (SeccompRule::new(vec![$($x),*]).unwrap())
}
/// Shorthand for chaining `SeccompRule`s with the `or` operator in a `SeccompFilter`.
///
/// [`SeccompFilter`]: struct.SeccompFilter.html
/// [`SeccompRule`]: struct.SeccompRule.html
macro_rules! or {
($($x:expr,)*) => (vec![$($x),*]);
($($x:expr),*) => (vec![$($x),*])
}
// See include/uapi/asm-generic/ioctls.h in the kernel code.
const TIOCGWINSZ: u64 = 0x5413;
const FIONBIO: u64 = 0x5421;
// See include/uapi/linux/vfio.h in the kernel code.
const VFIO_IOMMU_MAP_DMA: u64 = 0x3b71;
const VFIO_IOMMU_UNMAP_DMA: u64 = 0x3b72;
// See include/uapi/linux/if_tun.h in the kernel code.
const TUNSETOFFLOAD: u64 = 0x4004_54d0;
fn create_virtio_console_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ).unwrap()]]
}
fn create_virtio_iommu_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA).unwrap()],
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_UNMAP_DMA).unwrap()],
]
}
fn create_virtio_mem_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA).unwrap()],
and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_UNMAP_DMA).unwrap()],
]
}
fn virtio_balloon_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![(libc::SYS_fallocate, vec![])]
}
fn virtio_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_fallocate, vec![]),
(libc::SYS_fdatasync, vec![]),
(libc::SYS_fsync, vec![]),
(libc::SYS_ftruncate, vec![]),
(libc::SYS_getrandom, vec![]),
(libc::SYS_io_uring_enter, vec![]),
(libc::SYS_lseek, vec![]),
(libc::SYS_mprotect, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_pread64, vec![]),
(libc::SYS_preadv, vec![]),
(libc::SYS_pwritev, vec![]),
(libc::SYS_pwrite64, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_timerfd_settime, vec![]),
]
}
fn virtio_console_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_ioctl, create_virtio_console_ioctl_seccomp_rule()),
(libc::SYS_mprotect, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
]
}
fn virtio_iommu_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_ioctl, create_virtio_iommu_ioctl_seccomp_rule()),
(libc::SYS_mprotect, vec![]),
]
}
fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_fallocate, vec![]),
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_sendmsg, vec![]),
]
}
fn virtio_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_openat, vec![]),
(libc::SYS_readv, vec![]),
(libc::SYS_timerfd_settime, vec![]),
(libc::SYS_writev, vec![]),
]
}
fn create_virtio_net_ctl_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![and![Cond::new(1, ArgLen::Dword, Eq, TUNSETOFFLOAD).unwrap()],]
}
fn virtio_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![(libc::SYS_ioctl, create_virtio_net_ctl_ioctl_seccomp_rule())]
}
fn virtio_pmem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![(libc::SYS_fsync, vec![])]
}
fn virtio_rng_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_mprotect, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
]
}
fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_connect, vec![]),
(libc::SYS_nanosleep, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
(libc::SYS_socket, vec![]),
]
}
fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![]
}
fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_accept4, vec![]),
(libc::SYS_bind, vec![]),
(libc::SYS_getcwd, vec![]),
(libc::SYS_listen, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
(libc::SYS_socket, vec![]),
#[cfg(target_arch = "x86_64")]
(libc::SYS_unlink, vec![]),
#[cfg(target_arch = "aarch64")]
(libc::SYS_unlinkat, vec![]),
]
}
fn virtio_vhost_block_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![]
}
fn create_vsock_ioctl_seccomp_rule() -> Vec<SeccompRule> {
or![and![Cond::new(1, ArgLen::Dword, Eq, FIONBIO,).unwrap()],]
}
fn virtio_vsock_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_accept4, vec![]),
(libc::SYS_connect, vec![]),
(libc::SYS_ioctl, create_vsock_ioctl_seccomp_rule()),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_socket, vec![]),
]
}
fn virtio_watchdog_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_mprotect, vec![]),
(libc::SYS_prctl, vec![]),
(libc::SYS_sched_getaffinity, vec![]),
(libc::SYS_set_robust_list, vec![]),
(libc::SYS_timerfd_settime, vec![]),
]
}
fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
let mut rules = match thread_type {
Thread::VirtioBalloon => virtio_balloon_thread_rules(),
Thread::VirtioBlock => virtio_block_thread_rules(),
Thread::VirtioConsole => virtio_console_thread_rules(),
Thread::VirtioIommu => virtio_iommu_thread_rules(),
Thread::VirtioMem => virtio_mem_thread_rules(),
Thread::VirtioNet => virtio_net_thread_rules(),
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(),
};
rules.append(&mut virtio_thread_common());
rules
}
fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
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_madvise, vec![]),
(libc::SYS_mmap, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]
}
/// Generate a BPF program based on the seccomp_action value
pub fn get_seccomp_filter(
seccomp_action: &SeccompAction,
thread_type: Thread,
) -> Result<BpfProgram, Error> {
match seccomp_action {
SeccompAction::Allow => Ok(vec![]),
SeccompAction::Log => SeccompFilter::new(
get_seccomp_rules(thread_type).into_iter().collect(),
SeccompAction::Log,
SeccompAction::Allow,
std::env::consts::ARCH.try_into().unwrap(),
)
.and_then(|filter| filter.try_into())
.map_err(Error::Backend),
_ => SeccompFilter::new(
get_seccomp_rules(thread_type).into_iter().collect(),
SeccompAction::Trap,
SeccompAction::Allow,
std::env::consts::ARCH.try_into().unwrap(),
)
.and_then(|filter| filter.try_into())
.map_err(Error::Backend),
}
}