From 6706fac6f89044cbe66edb983ab912bc624561c5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 24 Jan 2025 23:40:52 +0100 Subject: [PATCH] seccomp: Restrict rlimit to get-self --- letmein-seccomp/src/lib.rs | 89 ++++++++++++++++++++++++++++---------- letmeinfwd/src/seccomp.rs | 2 +- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/letmein-seccomp/src/lib.rs b/letmein-seccomp/src/lib.rs index d59c639..57a75a9 100644 --- a/letmein-seccomp/src/lib.rs +++ b/letmein-seccomp/src/lib.rs @@ -15,6 +15,11 @@ use anyhow::{self as ah, Context as _}; use seccompiler::{apply_filter_all_threads, BpfProgram}; use std::env::consts::ARCH; +#[cfg(has_seccomp_support)] +const NULL: u64 = 0; +#[cfg(has_seccomp_support)] +const PTR: u8 = 0xFF; + #[cfg(has_seccomp_support)] macro_rules! sys { ($ident:ident) => {{ @@ -24,18 +29,42 @@ macro_rules! sys { }}; } +#[cfg(has_seccomp_support)] +fn seccomp_cond(idx: u8, value: u64, bit_width: u8) -> ah::Result { + use seccompiler::{SeccompCmpArgLen, SeccompCmpOp, SeccompCondition}; + + let bit_width = match bit_width { + PTR => { + #[cfg(target_pointer_width = "32")] + let bit_width = 32; + + #[cfg(target_pointer_width = "64")] + let bit_width = 64; + + bit_width + } + bit_width => bit_width, + }; + + let arglen = match bit_width { + 32 => { + assert_eq!(value & 0xFFFF_FFFF_0000_0000, 0); + SeccompCmpArgLen::Dword + } + 64 => SeccompCmpArgLen::Qword, + _ => unreachable!(), + }; + + Ok(SeccompCondition::new(idx, arglen, SeccompCmpOp::Eq, value)?) +} + #[cfg(has_seccomp_support)] macro_rules! args { - ($($arg:literal == $value:expr),*) => { + ($([ $arg:literal ] ($bit_width:expr) == $value:expr),*) => { SeccompRule::new( vec![ $( - SeccompCondition::new( - $arg, - SeccompCmpArgLen::Dword, - SeccompCmpOp::Eq, - ($value) as _, - )?, + seccomp_cond($arg, ($value) as _, $bit_width)?, )* ] )? @@ -80,7 +109,7 @@ pub enum Allow { Clone, Exec, Wait, - Rlimit, + GetRlimit, Uname, Pidfd, } @@ -106,10 +135,7 @@ impl Filter { pub fn compile_for_arch(allow: &[Allow], deny_action: Action, arch: &str) -> ah::Result { assert!(!allow.is_empty()); - use seccompiler::{ - SeccompAction, SeccompCmpArgLen, SeccompCmpOp, SeccompCondition, SeccompFilter, - SeccompRule, - }; + use seccompiler::{SeccompAction, SeccompFilter, SeccompRule}; use std::collections::BTreeMap; type RulesMap = BTreeMap>; @@ -197,33 +223,45 @@ impl Filter { } Allow::UnixAccept => { add_sys(&mut map, sys!(SYS_accept4)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_UNIX)); + add_sys_args_match(&mut map, sys!(SYS_socket), args!([0](32) == libc::AF_UNIX)); add_sys(&mut map, sys!(SYS_getsockopt)); add_sys(&mut map, sys!(SYS_getpeername)); } Allow::UnixConnect => { add_sys(&mut map, sys!(SYS_connect)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_UNIX)); + add_sys_args_match(&mut map, sys!(SYS_socket), args!([0](32) == libc::AF_UNIX)); add_sys(&mut map, sys!(SYS_getsockopt)); add_sys(&mut map, sys!(SYS_getpeername)); } Allow::TcpAccept => { add_sys(&mut map, sys!(SYS_accept4)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_INET)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_INET6)); + add_sys_args_match(&mut map, sys!(SYS_socket), args!([0](32) == libc::AF_INET)); + add_sys_args_match( + &mut map, + sys!(SYS_socket), + args!([0](32) == libc::AF_INET6), + ); add_sys(&mut map, sys!(SYS_getsockopt)); add_sys(&mut map, sys!(SYS_getpeername)); } Allow::TcpConnect => { add_sys(&mut map, sys!(SYS_connect)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_INET)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_INET6)); + add_sys_args_match(&mut map, sys!(SYS_socket), args!([0](32) == libc::AF_INET)); + add_sys_args_match( + &mut map, + sys!(SYS_socket), + args!([0](32) == libc::AF_INET6), + ); add_sys(&mut map, sys!(SYS_getsockopt)); add_sys(&mut map, sys!(SYS_getpeername)); } Allow::Netlink => { add_sys(&mut map, sys!(SYS_connect)); - add_sys_args_match(&mut map, sys!(SYS_socket), args!(0 == libc::AF_NETLINK)); + add_sys_args_match( + &mut map, + sys!(SYS_socket), + args!([0](32) == libc::AF_NETLINK), + ); add_sys(&mut map, sys!(SYS_getsockopt)); } Allow::SetSockOpt { level_optname } => { @@ -231,7 +269,7 @@ impl Filter { add_sys_args_match( &mut map, sys!(SYS_setsockopt), - args!(1 == level, 2 == optname), + args!([1](32) == level, [2](32) == optname), ); } else { add_sys(&mut map, sys!(SYS_setsockopt)); @@ -272,7 +310,7 @@ impl Filter { } Allow::Fcntl { op } => match op { Some(op) => { - add_sys_args_match(&mut map, sys!(SYS_fcntl), args!(1 == op)); + add_sys_args_match(&mut map, sys!(SYS_fcntl), args!([1](32) == op)); } None => { add_sys(&mut map, sys!(SYS_fcntl)); @@ -330,9 +368,12 @@ impl Filter { Allow::Wait => { add_sys(&mut map, sys!(SYS_wait4)); } - Allow::Rlimit => { - //TODO do we only need `get`? - add_sys(&mut map, sys!(SYS_prlimit64)); + Allow::GetRlimit => { + add_sys_args_match( + &mut map, + sys!(SYS_prlimit64), + args!([0](32) == 0, [2](PTR) == NULL), + ); } Allow::Uname => { add_sys(&mut map, sys!(SYS_uname)); diff --git a/letmeinfwd/src/seccomp.rs b/letmeinfwd/src/seccomp.rs index 78198b4..5667371 100644 --- a/letmeinfwd/src/seccomp.rs +++ b/letmeinfwd/src/seccomp.rs @@ -40,7 +40,7 @@ const ALLOW_LIST: [Allow; 29] = [ Allow::Clone, Allow::Exec, Allow::Wait, - Allow::Rlimit, + Allow::GetRlimit, Allow::Pidfd, ];