use serde::{Deserialize, Serialize};
pub const SECCOMP_PROFILE_VERSION: u32 = 1;
pub const BLOCKED_SYSCALLS: &[&str] = &[
"ptrace",
"kcmp",
"pidfd_getfd",
"process_madvise",
"process_mrelease",
"mount",
"umount",
"umount2",
"open_by_handle_at",
"name_to_handle_at",
"init_module",
"finit_module",
"delete_module",
"kexec_load",
"kexec_file_load",
"bpf",
"perf_event_open",
"userfaultfd",
"io_uring_setup",
"io_uring_enter",
"io_uring_register",
"process_vm_readv",
"process_vm_writev",
"reboot",
"swapon",
"swapoff",
"settimeofday",
"clock_settime",
"adjtimex",
"add_key",
"request_key",
"keyctl",
"ioperm",
"iopl",
"acct",
"quotactl",
"unshare",
"setns",
"personality",
];
pub const FILTERED_SYSCALLS: &[&str] = &[
"clone", "clone3", "ioctl", "prctl", "socket",
];
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SeccompProfile {
#[serde(default = "default_blocked_syscalls")]
blocked_syscalls: Vec<String>,
#[serde(default)]
pub(super) allow_namespaces: bool,
#[serde(default)]
pub(super) allow_network_sockets: bool,
#[serde(default)]
log_only: bool,
}
fn default_blocked_syscalls() -> Vec<String> {
BLOCKED_SYSCALLS.iter().map(|s| s.to_string()).collect()
}
impl Default for SeccompProfile {
fn default() -> Self {
Self {
blocked_syscalls: default_blocked_syscalls(),
allow_namespaces: false,
allow_network_sockets: false,
log_only: false,
}
}
}
impl SeccompProfile {
#[must_use]
pub(crate) fn blocked_syscalls(&self) -> &[String] {
&self.blocked_syscalls
}
#[must_use]
pub(crate) fn allow_namespaces(&self) -> bool {
self.allow_namespaces
}
#[must_use]
pub(crate) fn allow_network_sockets(&self) -> bool {
self.allow_network_sockets
}
#[must_use]
pub(crate) fn log_only(&self) -> bool {
self.log_only
}
#[must_use]
pub fn strict() -> Self {
Self {
blocked_syscalls: default_blocked_syscalls(),
allow_namespaces: false,
allow_network_sockets: false,
log_only: false,
}
}
#[must_use]
pub fn permissive() -> Self {
Self {
blocked_syscalls: vec![
"ptrace".to_string(),
"kexec_load".to_string(),
"kexec_file_load".to_string(),
"reboot".to_string(),
],
allow_namespaces: false,
allow_network_sockets: true,
log_only: false,
}
}
#[must_use]
pub fn logging() -> Self {
Self {
blocked_syscalls: default_blocked_syscalls(),
allow_namespaces: false,
allow_network_sockets: false,
log_only: true,
}
}
#[must_use]
pub fn block_syscall(mut self, syscall: impl Into<String>) -> Self {
let syscall = syscall.into();
if !self.blocked_syscalls.contains(&syscall) {
self.blocked_syscalls.push(syscall);
}
self
}
#[must_use]
pub fn with_network(mut self) -> Self {
self.allow_network_sockets = true;
self
}
#[must_use]
pub fn with_logging(mut self) -> Self {
self.log_only = true;
self
}
#[inline]
#[must_use]
pub(super) fn is_blocked(&self, syscall: &str) -> bool {
self.blocked_syscalls.iter().any(|s| s == syscall)
}
pub(crate) fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(self)
}
}