From 660b18eaace7953721c8ecf371973fc6eb6e2f66 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 28 Jul 2026 16:40:48 +0100 Subject: [PATCH] vmm: Clean up seccomp handling for glibc overcommit sysctl Unfortunately glibc can read the overcommit sysctl from any thread. This has lead to us adding a patchwork of openat/read syscalls to our allow list when those threads don't necessarily need openat for their actual uses. Only the VMM and migration worker thread have a strict requirement for the openat syscall. The syscall was added to the other threads to deal with this glibc behaviour. As read() is itself harmless move it to the common syscalls, strip full openat() from all but the threads that need it and add limited, read only, openat to all threads. Signed-off-by: Rob Bradford --- virtio-devices/src/seccomp_filters.rs | 15 +++++++-- vmm/src/seccomp_filters.rs | 46 ++++++++++++--------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs index 75f493448..7ed256a4d 100644 --- a/virtio-devices/src/seccomp_filters.rs +++ b/virtio-devices/src/seccomp_filters.rs @@ -8,7 +8,7 @@ use std::env; use block::{BLKDISCARD, BLKZEROOUT}; use libc::{FIONBIO, TIOCGWINSZ, TUNSETOFFLOAD}; -use seccompiler::SeccompCmpOp::Eq; +use seccompiler::SeccompCmpOp::{Eq, MaskedEq}; use seccompiler::{ BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen, SeccompCondition as Cond, SeccompFilter, SeccompRule, @@ -364,7 +364,18 @@ fn virtio_thread_common() -> Vec<(i64, Vec)> { (libc::SYS_mprotect, vec![]), (libc::SYS_mremap, vec![]), (libc::SYS_munmap, vec![]), - (libc::SYS_openat, vec![]), + ( + libc::SYS_openat, + or![and![ + Cond::new( + 2, // openat() flags argument + ArgLen::Dword, + MaskedEq(libc::O_ACCMODE as u64), + libc::O_RDONLY as u64, + ) + .unwrap() + ]], + ), (libc::SYS_read, vec![]), (libc::SYS_rt_sigprocmask, vec![]), (libc::SYS_rt_sigreturn, vec![]), diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index f5993758d..b1b18c768 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -13,9 +13,7 @@ use libc::{ TCGETS, TCGETS2, TCSETS, TCSETS2, TIOCGPGRP, TIOCGPTPEER, TIOCGWINSZ, TIOCSCTTY, TIOCSPGRP, TIOCSPTLCK, TUNGETFEATURES, TUNGETIFF, TUNSETIFF, TUNSETOFFLOAD, TUNSETVNETHDRSZ, }; -use seccompiler::SeccompCmpOp::Eq; -#[cfg(all(feature = "sev_snp", feature = "kvm"))] -use seccompiler::SeccompCmpOp::MaskedEq; +use seccompiler::SeccompCmpOp::{Eq, MaskedEq}; use seccompiler::{ BackendError, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen, SeccompCondition as Cond, SeccompFilter, SeccompRule, @@ -572,7 +570,11 @@ fn create_serial_manager_ioctl_seccomp_rule() -> Result, Backen // Syscalls needed by all threads, because they are used in the seccomp signal // handler. fn common_thread_rules() -> Result)>, BackendError> { - Ok(vec![(libc::SYS_gettid, vec![]), (libc::SYS_write, vec![])]) + Ok(vec![ + (libc::SYS_gettid, vec![]), + (libc::SYS_read, vec![]), + (libc::SYS_write, vec![]), + ]) } fn create_signal_handler_ioctl_seccomp_rule() -> Result, BackendError> { @@ -632,7 +634,6 @@ fn pty_foreground_thread_rules() -> Result)>, Backend (libc::SYS_poll, vec![]), #[cfg(target_arch = "aarch64")] (libc::SYS_ppoll, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_restart_syscall, vec![]), (libc::SYS_rt_sigaction, vec![]), (libc::SYS_rt_sigreturn, vec![]), @@ -732,7 +733,6 @@ fn vmm_thread_rules( (libc::SYS_prlimit64, vec![]), (libc::SYS_pwrite64, vec![]), (libc::SYS_pwritev, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_readv, vec![]), #[cfg(target_arch = "x86_64")] (libc::SYS_readlink, vec![]), @@ -938,10 +938,8 @@ fn vcpu_thread_rules( (libc::SYS_newfstatat, vec![]), #[cfg(target_arch = "x86_64")] (libc::SYS_open, vec![]), - (libc::SYS_openat, vec![]), (libc::SYS_pread64, vec![]), (libc::SYS_pwrite64, vec![]), - (libc::SYS_read, vec![]), #[cfg(target_arch = "x86_64")] (libc::SYS_readlink, vec![]), #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] @@ -993,19 +991,7 @@ fn http_api_thread_rules() -> Result)>, BackendError> (libc::SYS_mmap, vec![]), (libc::SYS_mprotect, vec![]), (libc::SYS_munmap, vec![]), - #[cfg(all(feature = "sev_snp", feature = "kvm"))] - ( - libc::SYS_openat, - or![and![Cond::new( - 2, // openat() flags argument - ArgLen::Dword, - MaskedEq(libc::O_ACCMODE as u64), - libc::O_RDONLY as u64, - )?]], - ), (libc::SYS_prctl, vec![]), - #[cfg(all(feature = "sev_snp", feature = "kvm"))] - (libc::SYS_read, vec![]), (libc::SYS_recvfrom, vec![]), (libc::SYS_recvmsg, vec![]), (libc::SYS_rt_sigprocmask, vec![]), @@ -1097,7 +1083,6 @@ fn migration_thread_rules() -> Result)>, BackendError #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] (libc::SYS_ppoll, vec![]), (libc::SYS_prctl, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_readv, vec![]), (libc::SYS_tkill, vec![]), (libc::SYS_recvfrom, vec![]), @@ -1139,14 +1124,12 @@ fn migration_tcp_worker_thread_rules() -> Result)>, B (libc::SYS_mmap, vec![]), (libc::SYS_mprotect, vec![]), (libc::SYS_munmap, vec![]), - (libc::SYS_openat, vec![]), #[cfg(target_arch = "x86_64")] (libc::SYS_poll, vec![]), #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] (libc::SYS_ppoll, vec![]), (libc::SYS_prctl, vec![]), (libc::SYS_pwrite64, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_readv, vec![]), (libc::SYS_recvfrom, vec![]), (libc::SYS_recvmsg, vec![]), @@ -1184,7 +1167,6 @@ fn serial_manager_thread_rules() -> Result)>, Backend (libc::SYS_mmap, vec![]), (libc::SYS_munmap, vec![]), (libc::SYS_nanosleep, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_recvfrom, vec![]), (libc::SYS_rt_sigprocmask, vec![]), (libc::SYS_rt_sigreturn, vec![]), @@ -1208,7 +1190,6 @@ fn migrate_send_postcopy_thread_rules() -> Result)>, (libc::SYS_mmap, vec![]), (libc::SYS_mprotect, vec![]), (libc::SYS_munmap, vec![]), - (libc::SYS_read, vec![]), (libc::SYS_recvfrom, vec![]), (libc::SYS_recvmsg, vec![]), (libc::SYS_rt_sigprocmask, vec![]), @@ -1244,6 +1225,21 @@ fn get_seccomp_rules( Thread::PtyForeground => pty_foreground_thread_rules()?, Thread::MigrateSendPostcopy => migrate_send_postcopy_thread_rules()?, }; + if !rules + .iter() + .chain(specific_rules.iter()) + .any(|(syscall, _)| *syscall == libc::SYS_openat) + { + rules.push(( + libc::SYS_openat, + or![and![Cond::new( + 2, // openat() flags argument + ArgLen::Dword, + MaskedEq(libc::O_ACCMODE as u64), + libc::O_RDONLY as u64, + )?]], + )); + } rules.extend(specific_rules); Ok(rules) }