caps
A pure-Rust library for reading, setting, and clearing Linux capabilities without any C dependency.
Repository Health
Technical Analysis
caps is a pure-Rust library for working with Linux capabilities, the fine-grained privilege system that lets processes hold specific superuser powers (like binding low ports or tracing other processes) instead of running as full root. It wraps the low-level capget/capset syscalls and prctl calls directly via libc, so it has no external C library dependency and works cleanly in statically-linked and musl targets.
The crate covers all five capability sets exposed by modern Linux kernels: the traditional POSIX Effective, Inheritable, and Permitted sets, plus the Linux-specific Ambient (since kernel 4.3) and Bounding (since kernel 2.6.25) sets. It also includes a runtime module for detecting at startup which sets and capabilities the currently running kernel actually supports, which matters because the capability list keeps growing across kernel releases.
What You Get
- A
Capabilityenum covering every POSIX and Linux-specific capability, plus aCapSetenum for the Effective, Inheritable, Permitted, Ambient, and Bounding sets. - Simple free functions —
read,has_cap,raise,drop,clear— that operate on any thread ID via directcapget/capset/prctlsyscalls, no libcap C bindings involved. - A
runtimemodule that detects which capability sets and individual capabilities the running kernel actually supports, via/procintrospection or live probing. - A
securebitsmodule for reading and setting the securebits flags that control how capabilities behave acrosssetuid/execveboundaries. - Optional
serde_supportfeature for serializing and deserializingCapabilityvalues. - Zero mandatory dependencies beyond
libc, keeping it lightweight enough for static and musl-linked binaries.
Common Use Cases
- Dropping unneeded root capabilities immediately after a privileged daemon binds a low port or opens a raw socket.
- Building container runtimes or sandboxing tools that need to construct a minimal capability set for a child process.
- Auditing or logging tools that report exactly which capabilities a running process currently holds.
- System utilities that need to detect, at runtime, whether the current kernel supports newer capability sets like Ambient before relying on them.
Under The Hood
Architecture — caps is organized into small, single-purpose modules that mirror the kernel’s own model: base.rs implements the POSIX Effective/Inheritable/Permitted sets via direct capget/capset syscalls against a CapUserHeader/CapUserData pair, ambient.rs and bounding.rs implement the two Linux-specific sets via prctl(PR_CAP_AMBIENT_*) and prctl(PR_CAPBSET_*) respectively, and nr.rs centralizes the raw kernel constants (capability numbers, prctl opcodes) that the other modules consume. The public lib.rs re-exports a small set of free functions (read, raise, drop, clear, has_cap) that dispatch to the right module based on the CapSet variant, giving callers one consistent entry point regardless of which underlying syscall mechanism a given set actually uses.
Tech Stack — the crate is intentionally minimal: libc is the only mandatory dependency, used purely for raw syscall/prctl bindings and C type definitions, with serde pulled in only behind the optional serde_support feature and serde_json used solely in dev-dependencies for tests. It targets Rust edition 2018 with an MSRV of 1.63, has no build script, and no code generation step, keeping the dependency tree and build surface deliberately thin.
Code Quality — the tests/ directory (208 lines across five files) exercises the ambient, bounding, effective, runtime, and securebits modules individually, and lib.rs embeds a runnable doc-example that doubles as an integration smoke test. Error handling is centralized in a single CapsError(String) wrapper implementing std::error::Error, which keeps call sites simple (?-friendly) at the cost of losing structured error variants; module- and item-level doc comments are present throughout, though there is no #![deny(missing_docs)] or clippy CI gate visible in the repo.
API Design — the public surface is small and consistent: five verb-named functions (read/raise/drop/clear/has_cap) that all take a CapSet plus an optional thread ID, paired with a self-documenting Capability enum whose variants are the actual CAP_* names from capabilities(7). Five runnable examples under examples/ (all_caps.rs, clear_permitted.rs, manipulate_sys_nice.rs, etc.) cover the realistic entry points, and the crate needs zero configuration or setup boilerplate — a caller can start reading capabilities in a single line.