Expand description
Types shared between the eBPF program (linprov-ebpf) and the userspace
daemon (linprov). Everything here is repr(C) and Pod-friendly so it
survives a round-trip through a ring buffer and a kernel xattr.
The crate compiles no_std by default (for the BPF target). Enable the
user feature in userspace to pull in bytemuck::Pod / Zeroable
derives on the wire types.
Wire shapes at a glance:
OriginRecordis what the daemon stores in the xattr and in the BPFINODE_MARKSmap. BPF writes most of it infile_open; userspace augmentscreator_pathfrom/proc/$pid/exe.Eventis the ringbuf record streamed from BPF to userspace.AllowRuleis one allowlist rule, packed into the BPFALLOW_RULESarray. String dims are stored asfnv_hashvalues so the BPF side can compare without carrying full byte arrays.
use linprov_common::{fnv_hash, dim};
// Both sides hash strings the same way; same input → same u64.
assert_eq!(fnv_hash("/usr/bin/curl"), fnv_hash("/usr/bin/curl"));
assert_ne!(fnv_hash("/usr/bin/curl"), fnv_hash("/usr/bin/wget"));
// Dimension bits are independent flags on AllowRule::flags.
let two_dim = dim::CREATOR_UID | dim::CREATOR_COMM;
assert_eq!(two_dim.count_ones(), 2);Modules§
- dim
flagsbits onAllowRule. Set bits indicate which dims this rule requires the record / execve context to match.
Structs§
- Allow
Rule - One allowlist rule. Set bits in
flagsmark required dims; the corresponding fields below are then compared against the record / execve context at enforce time. Cleared bits → field ignored. - Event
- Ring-buffer record. Two kinds:
NetworkFileOpen — informational; eBPF just wrote (or tried to write)
the xattr.
statusis the kfunc return code. Execve — bprm_check fired AND the file already carried the mark.originis the record we read back;statusis unused. - Origin
Record - Provenance record. Carried in the
security.bpf.linprov.originxattr and in the INODE_MARKS storage map.
Constants§
- COMM_
LEN - CREATOR_
PATH_ LEN - EVENT_
KIND_ EXECVE - EVENT_
KIND_ NETWORK_ FILE_ OPEN - FNV_
OFFSET - FNV_
PRIME - MAX_
FOLDER_ HASHES - Max number of
/-separated ancestor hashes we collect per filename for folder-rule matching. Each represents one ancestor directory (/,/opt/,/opt/installed/, …). Bounded so the verifier can reason about the rule-iteration loop and the inner folder match. - MAX_
RULES - Maximum number of allowlist rules carried by the BPF Array map. Each rule check is ~30 ops + 2 folder lookups; the verifier walks the full bounded loop, so this caps the per-execve cost.
- MODE_
ENFORCE - MODE_
OBSERVE - Runtime mode communicated to the eBPF program via the CONFIG map.
- MODE_
SOAK - ORIGIN_
VERSION - Current schema version of
OriginRecord. Records carrying a different version are treated as unmarked. - PATH_
HASH_ SCAN_ LEN - Max path length the BPF FNV walks inspect (one for
target_filename, one forlanding_filename, plus the folder-match walk). Bounded by the verifier’s 1M-insn budget acrossMAX_RULESwalks × per- rule per-dim scans. Linux paths can run toPATH_MAX(4096); for path-shaped rule values that exceed this scan length, soak truncates to a/-aligned ancestor (with a safety floor to keep rules from collapsing into the filesystem root). - PATH_
LEN - XATTR_
NAME
Functions§
- fnv_
hash - Hash a string with FNV-1a-64. Byte-by-byte, no trailing NUL, no padding — identical on the BPF and userspace sides.
- fnv_
hash_ bytes - Same as
fnv_hash, but takes a byte slice. Useful when the source isn’t UTF-8 (e.g., a[u8; PATH_LEN]filename buffer read out of a ringbuf event).