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 SeccompConditions, 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

Enums

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.