use eyre::{Result, eyre};
use nix::libc;
use seccompiler::{
BpfProgram, SeccompAction, SeccompCmpArgLen, SeccompCmpOp, SeccompCondition, SeccompFilter,
SeccompRule, TargetArch,
};
use std::collections::BTreeMap;
fn syscall_number<T: Into<i64>>(number: T) -> i64 {
number.into()
}
pub(super) fn apply_seccomp_filter(deny_net: bool, deny_process: bool) -> Result<()> {
let ret = unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) };
if ret != 0 {
return Err(eyre!(
"failed to set PR_SET_NO_NEW_PRIVS: {}",
std::io::Error::last_os_error()
));
}
let arch = std::env::consts::ARCH;
let target_arch = match arch {
"x86_64" => TargetArch::x86_64,
"aarch64" => TargetArch::aarch64,
_ => return Err(eyre!("unsupported architecture for seccomp: {arch}")),
};
let socket_rule_inet = SeccompRule::new(vec![SeccompCondition::new(
0, SeccompCmpArgLen::Dword,
SeccompCmpOp::Eq,
libc::AF_INET as u64,
)?])?;
let socket_rule_inet6 = SeccompRule::new(vec![SeccompCondition::new(
0,
SeccompCmpArgLen::Dword,
SeccompCmpOp::Eq,
libc::AF_INET6 as u64,
)?])?;
let mut rules: BTreeMap<i64, Vec<SeccompRule>> = BTreeMap::new();
if deny_net {
for syscall in [
syscall_number(libc::SYS_socket),
syscall_number(libc::SYS_socketpair),
] {
rules.insert(
syscall,
vec![socket_rule_inet.clone(), socket_rule_inet6.clone()],
);
}
}
if deny_process {
let deny = Vec::<SeccompRule>::new();
for syscall in [
syscall_number(libc::SYS_clone),
syscall_number(libc::SYS_clone3),
#[cfg(not(any(
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "loongarch64"
)))]
syscall_number(libc::SYS_fork),
#[cfg(not(any(
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "loongarch64"
)))]
syscall_number(libc::SYS_vfork),
syscall_number(libc::SYS_kill),
syscall_number(libc::SYS_tkill),
syscall_number(libc::SYS_tgkill),
syscall_number(libc::SYS_ptrace),
] {
rules.insert(syscall, deny.clone());
}
}
let filter: BpfProgram = SeccompFilter::new(
rules,
SeccompAction::Allow, SeccompAction::Errno(libc::EPERM as u32), target_arch,
)?
.try_into()?;
seccompiler::apply_filter(&filter).map_err(|e| eyre!("failed to apply seccomp filter: {e}"))?;
Ok(())
}