Skip to main content

Crate linprov_common

Crate linprov_common 

Source
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:

  • OriginRecord is what the daemon stores in the xattr and in the BPF INODE_MARKS map. BPF writes most of it in file_open; userspace augments creator_path from /proc/$pid/exe.
  • Event is the ringbuf record streamed from BPF to userspace.
  • AllowRule is one allowlist rule, packed into the BPF ALLOW_RULES array. String dims are stored as fnv_hash values 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
flags bits on AllowRule. Set bits indicate which dims this rule requires the record / execve context to match.

Structs§

AllowRule
One allowlist rule. Set bits in flags mark 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. status is the kfunc return code. Execve — bprm_check fired AND the file already carried the mark. origin is the record we read back; status is unused.
OriginRecord
Provenance record. Carried in the security.bpf.linprov.origin xattr 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 for landing_filename, plus the folder-match walk). Now equal to PATH_LEN — the walks run inside bpf_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 the bpf_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).