libseccomp
Safe, ergonomic Rust bindings for the libseccomp Linux syscall-filtering library
Repository Health
Technical Analysis
libseccomp is a Rust crate that wraps the libseccomp C library, giving Rust programs a safe, builder-style API for constructing Linux seccomp-BPF syscall filters. Instead of hand-writing raw BPF filter programs against the kernel’s syscall-filtering interface, developers use typed constructs like ScmpFilterContext, ScmpAction, and ScmpArch to define which syscalls a process is allowed to make, what happens when a disallowed syscall is attempted, and which CPU architectures the filter applies to.
The project ships as a two-crate Cargo workspace: libseccomp-sys provides raw, unsafe FFI bindings generated against the system libseccomp library, while libseccomp builds a safe, idiomatic Rust layer on top with Result-based error handling, deprecation-aware API evolution, and full rustdoc coverage. It is commonly used by container runtimes, sandboxing tools, and security-conscious CLI utilities that need fine-grained control over which system calls a process may execute.
What You Get
- A builder-pattern
ScmpFilterContextAPI for defining default actions, adding architectures, and appending per-syscall rules, then loading the compiled filter into the kernel - Typed
ScmpAction,ScmpArch,ScmpSyscall, andScmpCompareOptypes instead of raw libseccomp integer constants, with conversions to and from the underlying C values - A
Result-based error model (SeccompError/SeccompErrno) that maps every libseccomp C errno into a documented, matchable Rust enum instead of raw negative return codes - Seccomp user-space notification support (
notifymodule) for building filters that hand disallowed syscalls off to a supervising process instead of just killing or erroring - A companion
libseccomp-syscrate for callers who need the raw unsafe FFI surface directly, plus build-time linking against static, dynamic, or musl-built libseccomp via environment variables
Common Use Cases
- Sandboxing a container runtime or process supervisor by restricting the syscalls a spawned process may invoke before executing untrusted or lower-trust code
- Hardening a network-facing service (proxy, agent, daemon) by denying syscalls unrelated to its actual runtime needs, reducing the kernel attack surface if the process is compromised
- Building custom sandboxing or policy-enforcement tools that need to construct seccomp filters programmatically rather than shelling out to
seccomp-toolsor hand-writing BPF
Under The Hood
Architecture: The project is a two-crate Cargo workspace. libseccomp-sys exposes raw, unsafe extern "C" bindings and constants (e.g. SECCOMP_RET_ALLOW, seccomp_init) generated directly against the system libseccomp headers, with its own build.rs handling static/dynamic linking. libseccomp is the safe layer built on top: its central type, ScmpFilterContext (in filter_context.rs), wraps a NonNull<c_void> pointer returned by seccomp_init and exposes chainable methods (add_arch, add_rule, set_ctl_log, load) that call through to the sys crate and convert integer return codes to Result<()> via a shared cvt() helper in lib.rs. Supporting concerns are split into focused modules: action.rs (filter actions), arch.rs (architecture enum), syscall.rs plus a syscall/ directory of per-architecture syscall-number tables (x86_64, aarch64, arm, mips, riscv64, s390x, etc.), notify.rs (seccomp user-space notification API), filter_attr.rs, version.rs, and error.rs for the typed errno model.
Tech Stack: Rust edition 2021 with an MSRV of 1.67. Runtime dependencies are minimal and deliberate: bitflags 2.9 for flag types, libc 0.2.108 for C type/errno interop, and an optional cfg-if gated behind the const-syscall feature. libseccomp-sys is pulled in as a workspace-local path dependency pinned to 0.3.0. The crate is not a pure-Rust library — it links against the system libseccomp C library (>= 2.5.0, with a libseccomp_v2_6 cfg flag probed at build time via the pkg-config build-dependency), and supports static linking or musl cross-compilation through the LIBSECCOMP_LINK_TYPE / LIBSECCOMP_LIB_PATH environment variables — a real external-dependency install step (e.g. apt install libseccomp-dev) beyond cargo add.
Code Quality: The crate enforces strict lints at the crate root — deny(missing_debug_implementations), deny(missing_docs), deny(unsafe_op_in_unsafe_fn), plus warn-level clippy lints (unwrap_in_result, inefficient_to_string, clone_on_ref_ptr) — which forces every public item to carry documentation and keeps unsafe blocks explicit and auditable. Test coverage is substantial: a 513-line tests.rs plus notify.rs, global_reset.rs, and known_syscall_names.rs integration tests exercise real seccomp filters end-to-end via a syscall_assert! macro that triggers actual syscalls and checks the resulting errno, rather than only asserting on the Rust-level API surface. Errors are never left as bare negative return codes: SeccompError/SeccompErrno map every libseccomp errno to a documented variant with a human-readable strerror(), and the public API returns Result throughout rather than panicking.
API Design: The API favors a builder chain — ScmpFilterContext::new(ScmpAction::Allow)?.add_arch(...)?.add_rule(...)?.load()? — that mirrors how filters are actually assembled step by step, and getting a minimal working filter running requires only a handful of calls. Naming is consistently Scmp-prefixed across every public type (ScmpAction, ScmpArch, ScmpFilterContext, ScmpSyscall, ScmpVersion), which makes the API’s surface easy to recognize in IDE autocomplete. Every public function carries a doc comment with a runnable doctest example and, where applicable, a link to the corresponding libseccomp man page, and superseded methods (e.g. new_filter) are kept as #[deprecated] aliases with migration notes rather than being silently removed.