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). Now equal toPATH_LEN— the walks run insidebpf_loop(), so the verifier inspects the loop body once instead of unrolling it across iterations, and the scan length is bounded only by the buffer size, not by the verifier’s instruction budget. Older builds capped this at 80; bumped to 256 alongside thebpf_loop-based walk refactor. - 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).