cloud-hypervisor/virtio-devices/src/seccomp_filters.rs
Rob Bradford f30d460fa3 virtio-devices: seccomp: Move mprotect() to virtio common rules
It's perfectly reasonable to expect if that some virtio threads trigger
libc behaviour that needs mprotect() that all virtio threads would do
the same.

Fixes: #4874

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-11-12 08:29:47 +00:00

286 lines
9.0 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())
}
/// 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_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_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())]
}
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_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_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_pread64, vec![]),
(libc::SYS_pwrite64, 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_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_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![]),
(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_mprotect, vec![]),
(libc::SYS_munmap, vec![]),
(libc::SYS_openat, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_rt_sigreturn, 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),
}
}