This document describes BPFContain's project layout and explains what each source file does. The goal is to help new contributors develop a mental model of what BPFContain is, what technologies it relies on, and how it works.
This file contains definitions for the eBPF programs and maps that make BPFContain work. For this, we leverage libbpf and BPF CO-RE, which provides several convenience helpers for loading and managing eBPF programs as well as "compile once, run everywhere" functionality.
On the Rust side, we use libbpf-rs which provides
safe Rust bindings for libbpf. We use the accompanying libbpf-cargo
crate to build the
eBPF programs and generate a Rust skeleton file for easy program management.
- LSM Programs
- LSM programs define an interface for attaching BPF programs to LSM security hooks.
- These form the backbone of BPFContain's policy enforcement.
- LSM programs are annotated with the
SEC("lsm/<target>")
section label and are defined using libbpf'sBPF_PROG(name, args...)
helper macro. - They begin by filtering the current task to make sure that it is confined, then return a policy decision (0 means allowed, -EACCES means denied).
- BTF Tracepoints
- Tracepoints define a stable tracing interface for attaching BPF programs.
- These are used for basic bookkeeping (i.e. keeping track of processes, and which policy and "container" they belong to).
- They are annotated with the
SEC("tp_btf/<target>")
section label.
- Uprobes
- Uprobes allow BPF programs to be attached to target addresses in userspace applications.
- In BPFContain, we use uprobes to provide an interface for userspace to interact with our eBPF programs.
- They are annotated with the
SEC("uprobe/<target>")
section label. - Currently, we have one uprobe that allows a process to "containerize" itself.
All of BPFContain's maps are defined in src/bpf/include/map_defs.h
.
- Processes Map
- This map caches information about actively confined processes and is used to implement filtering logic for the LSM programs.
- Containers Map
- This map caches information about active containers including which policy they are associated with along with other properties like taintedness.
- Policy Maps
- These are eBPF hash maps that define a mapping between policy "keys" and "values".
- There are several policy maps, one per policy type.
- The keys are comprised of a "policy id" along with the necessary data to describe the requested system object (e.g. inode and device number for a file).
- The values are three bit vectors:
allowed
,tainted
, anddenied
. Each of these vectors defines a bitmask which represents the corresponding access to the requested object.allowed
must be a superset of the requested access for access to be granted.tainted
can be any subset of the requested access for the process to become tainted.denied
can be any subset of the requested access for access to be denied.
- "Tainting" is a feature of BPFContain which triggers default-deny enforcement (i.e. if access is not explicitly allowed, it is assumed to be denied). Once a process becomes tainted, it can never become untainted.
These files are automatically generated by libbpf-cargo
when building the project. They
are not included in the repository proper.