Crate seccompiler
source ·Expand description
Provides easy-to-use Linux seccomp-bpf jailing.
Seccomp is a Linux kernel security feature which enables a tight control over what kernel-level mechanisms a process has access to. This is typically used to reduce the attack surface and exposed resources when running untrusted code. This works by allowing users to write and set a BPF (Berkeley Packet Filter) program for each process or thread, that intercepts syscalls and decides whether the syscall is safe to execute.
Writing BPF programs by hand is difficult and error-prone. This crate provides high-level wrappers for working with system call filtering.
The core concept of the library is the filter. It is an abstraction that models a collection of syscall-mapped rules, coupled with on-match and default actions, that logically describes a policy for dispatching actions (e.g. Allow, Trap, Errno) for incoming system calls.
Seccompiler provides constructs for defining filters, compiling them into loadable BPF programs and installing them in the kernel.
Filters are defined either with a JSON file or using Rust code, with library-defined structures. Both representations are semantically equivalent and model the rules of the filter. Choosing one or the other depends on the use case and preference.
Supported platforms
Due to the fact that seccomp is a Linux-specific feature, this crate is supported only on Linux systems.
Supported host architectures:
- Little-endian x86_64
- Little-endian aarch64
Terminology
The smallest unit of the SeccompFilter
is the SeccompCondition
, which is a
comparison operation applied to the current system call. It’s parametrised by
the argument index, the length of the argument, the operator and the actual
expected value.
Going one step further, a SeccompRule
is a vector of SeccompCondition
s,
that must all match for the rule to be considered matched. In other words, a
rule is a collection of and-bound conditions for a system call.
Finally, at the top level, there’s the SeccompFilter
. The filter can be
viewed as a collection of syscall-associated rules, with a predefined on-match
SeccompAction
and a default SeccompAction
that is returned if none of the rules match.
In a filter, each system call number maps to a vector of or-bound rules. In order for the filter to match, it is enough that one rule associated to the system call matches. A system call may also map to an empty rule vector, which means that the system call will match, regardless of the actual arguments.
Examples
The following example defines and installs a simple Rust filter, that sends SIGSYS for
accept4
, fcntl(any, F_SETFD, FD_CLOEXEC, ..)
and fcntl(any, F_GETFD, ...)
.
It allows any other syscalls.
use seccompiler::{
BpfProgram, SeccompAction, SeccompCmpArgLen, SeccompCmpOp, SeccompCondition, SeccompFilter,
SeccompRule,
};
use std::convert::TryInto;
let filter: BpfProgram = SeccompFilter::new(
vec![
(libc::SYS_accept4, vec![]),
(
libc::SYS_fcntl,
vec![
SeccompRule::new(vec![
SeccompCondition::new(
1,
SeccompCmpArgLen::Dword,
SeccompCmpOp::Eq,
libc::F_SETFD as u64,
)
.unwrap(),
SeccompCondition::new(
2,
SeccompCmpArgLen::Dword,
SeccompCmpOp::Eq,
libc::FD_CLOEXEC as u64,
)
.unwrap(),
])
.unwrap(),
SeccompRule::new(vec![SeccompCondition::new(
1,
SeccompCmpArgLen::Dword,
SeccompCmpOp::Eq,
libc::F_GETFD as u64,
)
.unwrap()])
.unwrap(),
],
),
]
.into_iter()
.collect(),
SeccompAction::Allow,
SeccompAction::Trap,
std::env::consts::ARCH.try_into().unwrap(),
)
.unwrap()
.try_into()
.unwrap();
seccompiler::apply_filter(&filter).unwrap();
This second example defines and installs an equivalent JSON filter (uses the json
feature):
use seccompiler::BpfMap;
use std::convert::TryInto;
let json_input = r#"{
"main_thread": {
"mismatch_action": "allow",
"match_action": "trap",
"filter": [
{
"syscall": "accept4"
},
{
"syscall": "fcntl",
"args": [
{
"index": 1,
"type": "dword",
"op": "eq",
"val": 2,
"comment": "F_SETFD"
},
{
"index": 2,
"type": "dword",
"op": "eq",
"val": 1,
"comment": "FD_CLOEXEC"
}
]
},
{
"syscall": "fcntl",
"args": [
{
"index": 1,
"type": "dword",
"op": "eq",
"val": 1,
"comment": "F_GETFD"
}
]
}
]
}
}"#;
let filter_map: BpfMap = seccompiler::compile_from_json(
json_input.as_bytes(),
std::env::consts::ARCH.try_into().unwrap(),
)
.unwrap();
let filter = filter_map.get("main_thread").unwrap();
seccompiler::apply_filter(&filter).unwrap();
Structs
- Condition that a syscall must match in order to satisfy a rule.
- Filter containing rules assigned to syscall numbers.
- Rule that a filter attempts to match for a syscall.
- BPF instruction structure definition.
Enums
- Backend-related errors.
- Library errors.
- Actions that a seccomp filter can return for a syscall.
- Seccomp argument value length.
- Comparison to perform when matching a condition.
- Supported target architectures.
Functions
- Apply a BPF filter to the calling thread.
- Apply a BPF filter to the all threads in the process via the TSYNC feature. Please read the man page for seccomp (
man 2 seccomp
) for more information.
Type Aliases
BpfMap
is another type exposed by the library, which maps thread categories to BPF programs.- Program made up of a sequence of BPF instructions.
- Reference to program made up of a sequence of BPF instructions.
- Library Result type.