provctl is a process/file/network provenance tracker and flight recorder for Linux. One capture engine, backed by five eBPF hooks, answers the two questions a forensics tool actually exists for.
The kernel side stays deliberately dumb: capture events, tag them with identity, hand them to userspace. Every interesting question is a query over one durable event log, not a separate subsystem.
Attaches five eBPF hooks (fork/exec/exit, file opens, TCP connects) and streams live, colorized events to a persistent SQLite store.
Reconstructs a file's provenance: who wrote it, who reopened it, who executed it, and what that execution did next.
The full recorded life of one process β every file it opened, every connection it made, every child it spawned β merged and sorted by time.
The recorded process tree, reconstructed from parent/child relationships captured at fork time.
A live TUI: process tree on the left, scrolling activity feed on the right β a separate, unprivileged process reading the same store watch is writing to.
Compiled once, runs across kernel versions that expose the same fields β no recompiling per target, no kernel headers needed at runtime.
Five eBPF hooks feed one ring buffer. A Go daemon decodes that stream and persists it to SQLite (WAL mode, batched writes). Every CLI command is a read-only query over that same store.
kernel userspace βββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β tp/sched_process_fork β β β β tp/sched_process_exec β β engine.Engine β β tp/sched_process_exit ββββΆβ - loads probes (bpf2go) β β fentry/security_file_open β β - attaches all hooks β β fentry/tcp_v4_connect β β - reads BPF ring buffer β β fentry/tcp_v6_connect β β - decodes -> model.Event β ββββββββββββββββ¬βββββββββββββββββ βββββββββββββββββ¬βββββββββββββββ β BPF ring buffer β β (struct event, provctl.h) βΌ β ββββββββββββββββββββββββ β β store.Store (SQLite) β βββββββββββββββββββββββββββΆβ processes β β file_events β β net_events β β activity_log β ββββββββββββ¬βββββββββββββ β ββββββββββββββββββββ¬ββββββββββββββββΌββββββββββββββββββββ¬βββββββββββββββββββ βΌ βΌ βΌ βΌ provctl trace provctl timeline provctl ps provctl top
No C dependencies β both eBPF and SQLite bindings are pure Go, so it's a single static binary.
# clone, build, install globally (needed so `sudo provctl watch` can find it) git clone https://github.com/thefoulowl/provctl cd provctl go build -trimpath -o provctl ./cmd/provctl sudo install -Dm755 provctl /usr/local/bin/provctl
go install github.com/thefoulowl/provctl/cmd/provctl@latest # lands in $(go env GOPATH)/bin β put that on PATH. # note: sudo provctl watch needs the binary on root's PATH too, # which ~/go/bin usually isn't. See the README for the full story.
rpmbuild -bb packaging/rpm/provctl.spec # or via Fedora COPR, once published β see the wiki
cd packaging/deb dpkg-buildpackage -us -uc -b
cd packaging/aur makepkg -si
Requires a kernel exposing BTF at /sys/kernel/btf/vmlinux (5.8+, default on most distros since ~2021).
Start capturing as root, then ask questions from anywhere β the read-only commands need no privileges beyond file access.
| Command | Access | What it does |
|---|---|---|
provctl watch | root | Attaches the probes, streams events, persists them to SQLite. |
provctl trace <path> | unprivileged | Reconstructs a file's provenance chain. |
provctl timeline <pid> | unprivileged | Every recorded event for one process, time-sorted. |
provctl ps | unprivileged | The recorded process tree. |
provctl top | unprivileged | Live TUI: process tree + scrolling activity feed. |