diff --git a/Cargo.toml b/Cargo.toml index 0df83978a..e24c90c35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,7 +132,7 @@ mount = [] net = ["linux-raw-sys/net", "linux-raw-sys/netlink", "linux-raw-sys/if_ether", "linux-raw-sys/xdp"] # Enable `rustix::thread::*`. -thread = ["linux-raw-sys/prctl"] +thread = ["linux-raw-sys/prctl", "linux-raw-sys/ptrace"] # Enable `rustix::process::*`. process = ["linux-raw-sys/prctl"] diff --git a/src/backend/libc/thread/syscalls.rs b/src/backend/libc/thread/syscalls.rs index 9198a7fbe..e6550b5db 100644 --- a/src/backend/libc/thread/syscalls.rs +++ b/src/backend/libc/thread/syscalls.rs @@ -778,3 +778,22 @@ pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<( )) } } + +#[cfg(linux_kernel)] +pub(crate) fn seccomp( + operation: SeccompOperation, + flags: Option, + args: *mut c::c_void, +) -> io::Result<()> { + syscall! { + fn seccomp(operation: SeccompOperation, flags: c::c_uint, args: *mut c::c_void) via SYS_seccomp -> c::c_int + } + + unsafe { + ret(seccomp( + operation, + flags.map_or(0, |flags| flags.bits()), + args, + )) + } +} diff --git a/src/backend/libc/thread/types.rs b/src/backend/libc/thread/types.rs index 105749ed9..2d41d1be9 100644 --- a/src/backend/libc/thread/types.rs +++ b/src/backend/libc/thread/types.rs @@ -58,3 +58,12 @@ pub(crate) fn raw_cpu_set_new() -> RawCpuSet { #[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))] pub(crate) const CPU_SETSIZE: usize = c::CPU_SETSIZE as usize; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u32)] +pub(crate) enum SeccompOperation { + SetModeStrict = libc::SECCOMP_SET_MODE_STRICT, + SetModeFilter = libc::SECCOMP_SET_MODE_FILTER, + GetActionAvailable = libc::SECCOMP_GET_ACTION_AVAIL, + GetNotifSizes = libc::SECCOMP_GET_NOTIF_SIZES, +} diff --git a/src/backend/linux_raw/c.rs b/src/backend/linux_raw/c.rs index 4dc9c8cd7..41aa1a0a1 100644 --- a/src/backend/linux_raw/c.rs +++ b/src/backend/linux_raw/c.rs @@ -367,6 +367,12 @@ mod statx_flags { STATX_ATTR_VERITY, }; } +#[cfg(feature = "thread")] +pub(crate) use linux_raw_sys::ptrace::{ + sock_filter, sock_fprog, SECCOMP_FILTER_FLAG_LOG, SECCOMP_FILTER_FLAG_NEW_LISTENER, + SECCOMP_FILTER_FLAG_SPEC_ALLOW, SECCOMP_FILTER_FLAG_TSYNC, SECCOMP_FILTER_FLAG_TSYNC_ESRCH, + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, +}; #[cfg(any( feature = "fs", all( diff --git a/src/backend/linux_raw/conv.rs b/src/backend/linux_raw/conv.rs index 901451ae6..7188569f6 100644 --- a/src/backend/linux_raw/conv.rs +++ b/src/backend/linux_raw/conv.rs @@ -666,6 +666,24 @@ impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { } } +#[cfg(feature = "thread")] +impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { + #[inline] + fn from(operation: super::thread::types::SeccompOperation) -> Self { + c_uint(operation as u32) + } +} + +#[cfg(feature = "thread")] +impl<'a, Num: ArgNumber> From> + for ArgReg<'a, Num> +{ + #[inline] + fn from(operation: Option) -> Self { + c_uint(operation.map_or(0, |flags| flags.bits())) + } +} + #[cfg(target_pointer_width = "64")] #[inline] pub(super) fn dev_t<'a, Num: ArgNumber>(dev: u64) -> ArgReg<'a, Num> { diff --git a/src/backend/linux_raw/thread/syscalls.rs b/src/backend/linux_raw/thread/syscalls.rs index 352e06150..4f99e9d91 100644 --- a/src/backend/linux_raw/thread/syscalls.rs +++ b/src/backend/linux_raw/thread/syscalls.rs @@ -15,7 +15,8 @@ use crate::fd::BorrowedFd; use crate::io; use crate::pid::Pid; use crate::thread::{ - futex, ClockId, Cpuid, MembarrierCommand, MembarrierQuery, NanosleepRelativeResult, Timespec, + futex, ClockId, Cpuid, MembarrierCommand, MembarrierQuery, NanosleepRelativeResult, + SetSecureComputingFilterFlags, Timespec, }; use crate::utils::as_mut_ptr; use core::mem::MaybeUninit; @@ -547,3 +548,12 @@ pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<( )) } } + +#[cfg(linux_kernel)] +pub(crate) fn seccomp( + operation: super::types::SeccompOperation, + flags: Option, + args: *mut c::c_void, +) -> io::Result { + unsafe { ret_c_int(syscall!(__NR_seccomp, operation, flags, args)) } +} diff --git a/src/backend/linux_raw/thread/types.rs b/src/backend/linux_raw/thread/types.rs index be92235e8..fbb3b1df4 100644 --- a/src/backend/linux_raw/thread/types.rs +++ b/src/backend/linux_raw/thread/types.rs @@ -60,3 +60,12 @@ pub(crate) fn raw_cpu_set_new() -> RawCpuSet { } pub(crate) const CPU_SETSIZE: usize = 8 * core::mem::size_of::(); + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u32)] +pub(crate) enum SeccompOperation { + SetModeStrict = linux_raw_sys::ptrace::SECCOMP_SET_MODE_STRICT, + SetModeFilter = linux_raw_sys::ptrace::SECCOMP_SET_MODE_FILTER, + GetActionAvailable = linux_raw_sys::ptrace::SECCOMP_GET_ACTION_AVAIL, + GetNotifSizes = linux_raw_sys::ptrace::SECCOMP_GET_NOTIF_SIZES, +} diff --git a/src/thread/mod.rs b/src/thread/mod.rs index 26d1de427..ebbcc5ecb 100644 --- a/src/thread/mod.rs +++ b/src/thread/mod.rs @@ -16,6 +16,8 @@ mod prctl; mod sched; mod sched_yield; #[cfg(linux_kernel)] +mod seccomp; +#[cfg(linux_kernel)] mod setns; #[cfg(not(target_os = "redox"))] @@ -34,4 +36,6 @@ pub use prctl::*; pub use sched::*; pub use sched_yield::sched_yield; #[cfg(linux_kernel)] +pub use seccomp::*; +#[cfg(linux_kernel)] pub use setns::*; diff --git a/src/thread/prctl.rs b/src/thread/prctl.rs index 2f439590e..54f5da292 100644 --- a/src/thread/prctl.rs +++ b/src/thread/prctl.rs @@ -168,6 +168,10 @@ const PR_SET_SECCOMP: c_int = 22; /// - [`prctl(PR_SET_SECCOMP,…)`] /// /// [`prctl(PR_SET_SECCOMP,…)`]: https://man7.org/linux/man-pages/man2/prctl.2.html +#[deprecated( + since = "1.1.0", + note = "Use set_secure_computing_mode_strict/set_secure_computing_mode_filter" +)] #[inline] pub fn set_secure_computing_mode(mode: SecureComputingMode) -> io::Result<()> { unsafe { prctl_2args(PR_SET_SECCOMP, mode as usize as *mut _) }.map(|_r| ()) diff --git a/src/thread/seccomp.rs b/src/thread/seccomp.rs new file mode 100644 index 000000000..7e37e4e1a --- /dev/null +++ b/src/thread/seccomp.rs @@ -0,0 +1,73 @@ +use core::marker::PhantomData; +use core::ptr::null_mut; + +use bitflags::bitflags; + +use crate::backend::c; +use crate::backend::thread::syscalls; +use crate::backend::thread::types::SeccompOperation; +use crate::io; + +bitflags! { + /// fixme + pub struct SetSecureComputingFilterFlags: u32 { + /// fixme + const TSYNC = c::SECCOMP_FILTER_FLAG_TSYNC; + /// fixme + const LOG = c::SECCOMP_FILTER_FLAG_LOG; + /// fixme + const SPEC_ALLOW = c::SECCOMP_FILTER_FLAG_SPEC_ALLOW; + /// fixme + const NEW_LISTENER = c::SECCOMP_FILTER_FLAG_NEW_LISTENER; + /// fixme + const TSYNC_ESRCH = c::SECCOMP_FILTER_FLAG_TSYNC_ESRCH; + /// fixme + const WAIT_KILLABLE_RECV = c::SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV; + + const _ = !0; + } +} + +/// fixme +#[derive(Debug)] +#[repr(transparent)] +pub struct SecureComputingFilterLine(c::sock_filter); + +/// fixme +#[derive(Debug)] +#[repr(transparent)] +pub struct SecureComputingFilter<'a>(c::sock_fprog, PhantomData<&'a [SecureComputingFilterLine]>); +impl<'a> From<&'a [SecureComputingFilterLine]> for SecureComputingFilter<'a> { + fn from(filter_lines: &'a [SecureComputingFilterLine]) -> Self { + Self( + c::sock_fprog { + // usize as u16 is lossy. However filter programs with more than BPF_MAXINSNS (4096) + // will be rejected by the kernel with EINVAL. + len: filter_lines.len() as u16, + filter: filter_lines.as_ptr() as *mut c::sock_filter, + }, + PhantomData, + ) + } +} + +/// fixme +pub fn set_secure_computing_mode_strict() -> io::Result<()> { + syscalls::seccomp(SeccompOperation::SetModeStrict, None, null_mut()).map(|_| ()) +} + +/// fixme +/// +/// ... low level interface ... you likely want to use a library like libseccomp. +/// +/// ... return value can be anything .... no I/O Safety ... +pub fn set_secure_computing_mode_filter( + filter: &SecureComputingFilter, + flags: SetSecureComputingFilterFlags, +) -> io::Result { + syscalls::seccomp( + SeccompOperation::SetModeFilter, + Some(flags), + filter as *const _ as *mut c::c_void, + ) +}