Hi thanks for this project, I just started using it and I noticed that filesystem violations are not recorded, so here is a deepseek analysis:
Following the documented rootless setup for eBPF violation monitoring, fence -m starts without any error but logs zero filesystem violation lines. The documented setcap workaround cannot work, and the monitor's failure to start is silently discarded, leaving users with an empty --fence-log-file and no indication that filesystem monitoring is not running.
Environment
- fence v0.1.66 (Linux x86_64, Fedora 44 kernel)
- bpftrace v0.24.2
kernel.unprivileged_bpf_disabled = 2
Steps to reproduce
- Install bpftrace + socat + bwrap.
- Follow the documented rootless recipe from
docs/linux-security-features.md:
sudo setcap cap_bpf+ep /usr/local/bin/fence
- Configure a sandbox that will produce a violation (e.g. run an app that writes to a path outside
allowWrite).
- Run in monitor mode:
fence -m --fence-log-file fence.log --settings fence.json <cmd>
- Observe that
fence.log stays empty even though the sandboxed app fails with "read-only file system" / EACCES on writes.
Expected
- With
-m + working CAP_BPF, denied filesystem syscalls appear as [fence:ebpf] lines in the log (this is what the docs promise: "Blocked filesystem access + syscalls").
- If the eBPF monitor cannot actually run, fence should surface that clearly (not silently), and the docs' rootless instructions should be correct.
Actual
- Non-debug run:
fence.log is completely empty, no warning of any kind.
- Debug run (
-d) reveals the failure:
[fence:ebpf] Started eBPF monitoring for PID 1725418
[fence:ebpf:err] ERROR: bpftrace currently only supports running as the root user.
Root cause analysis
-
Caps on the fence binary don't reach bpftrace. The eBPF monitor does not load BPF itself — it shells out to the bpftrace executable (internal/sandbox/linux_ebpf.go, tryBpftrace → exec.LookPath("bpftrace")). The file capabilities on fence live in its effective/permitted sets with an empty inheritable set, so they are never inherited by the bpftrace child process. The documented setcap cap_bpf+ep /usr/local/bin/fence therefore has no effect on the actual BPF workload.
-
bpftrace v0.24.2 hard-requires geteuid() == 0 and ignores capabilities entirely. check_is_root() in src/run_bpftrace.cpp (v0.24.2) is:
void check_is_root()
{
if (geteuid() != 0) {
LOG(ERROR) << "bpftrace currently only supports running as the root user.";
exit(1);
}
}
There is no capability-based acceptance path. Even setcap cap_bpf,cap_perfmon,cap_sys_admin+ep on the bpftrace binary is rejected (verified: same error). So "grant CAP_BPF" cannot work for filesystem violation monitoring with the current bpftrace, and sudo is the only real option.
-
The monitor failure is silently swallowed. cmd/fence/main.go:
linuxMonitors, _ = sandbox.StartLinuxMonitor(execCmd.Process.Pid, ...)
The error is discarded. EBPFMonitor.Start() only logs its failures via fencelog.Printf gated on m.debug, and tryBpftrace returns nil once bpftrace starts (the child dies asynchronously). Result: -m reports success, the monitor is dead, and — because nothing else is denied — the log file stays empty with no diagnostic.
Suggested fixes (any subset)
- Detect and warn (not debug-gated): before/after starting the eBPF monitor, verify the
bpftrace binary is present and usable (e.g. run bpftrace --version or an attach smoke-test), and emit an unconditional [fence:ebpf] warning when filesystem monitoring will not be active. Also stop discarding StartLinuxMonitor's error in cmd/fence/main.go.
- Make rootless work or say it can't: since bpftrace ≥ v0.24.2 gates on
geteuid()==0, either (a) run bpftrace through a rootless-capable path (e.g. invoke via a setuid/sudo wrapper, or exec bpftrace under the granted capabilities by setting the inheritable set), or (b) update docs/linux-security-features.md to state plainly that filesystem violation monitoring on Linux requires running fence as root, and that the setcap cap_bpf+ep fence recipe only enables... (nothing observable today).
- Docs fix: correct the "grant CAP_BPF" section (
Enabling eBPF Monitoring) so it doesn't promise a working rootless path, and note the --linux-features "CAP_BPF available" status is misleading because it checks fence's own caps, not the bpftrace child's ability to run.
- Consider not requiring root: replace the
bpftrace dependency with an in-process eBPF tracepoint program (fence already uses libbpf-style BPF for its seccomp filter), which would make CAP_BPF on the fence binary actually sufficient.
Notes
- Network denials (
[fence:http]/[fence:socks]) log fine without root; only filesystem/syscall violations are affected.
--linux-features currently reports eBPF monitor ... ok (CAP_BPF available) even when this failure will occur, since it checks the fence process's own capabilities rather than end-to-end monitor viability.
Hi thanks for this project, I just started using it and I noticed that filesystem violations are not recorded, so here is a deepseek analysis:
Following the documented rootless setup for eBPF violation monitoring,
fence -mstarts without any error but logs zero filesystem violation lines. The documentedsetcapworkaround cannot work, and the monitor's failure to start is silently discarded, leaving users with an empty--fence-log-fileand no indication that filesystem monitoring is not running.Environment
kernel.unprivileged_bpf_disabled = 2Steps to reproduce
docs/linux-security-features.md:allowWrite).fence.logstays empty even though the sandboxed app fails with "read-only file system" / EACCES on writes.Expected
-m+ working CAP_BPF, denied filesystem syscalls appear as[fence:ebpf]lines in the log (this is what the docs promise: "Blocked filesystem access + syscalls").Actual
fence.logis completely empty, no warning of any kind.-d) reveals the failure:Root cause analysis
Caps on the
fencebinary don't reachbpftrace. The eBPF monitor does not load BPF itself — it shells out to thebpftraceexecutable (internal/sandbox/linux_ebpf.go,tryBpftrace→exec.LookPath("bpftrace")). The file capabilities onfencelive in its effective/permitted sets with an empty inheritable set, so they are never inherited by thebpftracechild process. The documentedsetcap cap_bpf+ep /usr/local/bin/fencetherefore has no effect on the actual BPF workload.bpftrace v0.24.2 hard-requires
geteuid() == 0and ignores capabilities entirely.check_is_root()insrc/run_bpftrace.cpp(v0.24.2) is:There is no capability-based acceptance path. Even
setcap cap_bpf,cap_perfmon,cap_sys_admin+epon thebpftracebinary is rejected (verified: same error). So "grant CAP_BPF" cannot work for filesystem violation monitoring with the current bpftrace, andsudois the only real option.The monitor failure is silently swallowed.
cmd/fence/main.go:The error is discarded.
EBPFMonitor.Start()only logs its failures viafencelog.Printfgated onm.debug, andtryBpftracereturnsnilonce bpftrace starts (the child dies asynchronously). Result:-mreports success, the monitor is dead, and — because nothing else is denied — the log file stays empty with no diagnostic.Suggested fixes (any subset)
bpftracebinary is present and usable (e.g. runbpftrace --versionor an attach smoke-test), and emit an unconditional[fence:ebpf]warning when filesystem monitoring will not be active. Also stop discardingStartLinuxMonitor's error incmd/fence/main.go.geteuid()==0, either (a) runbpftracethrough a rootless-capable path (e.g. invoke via a setuid/sudo wrapper, or exec bpftrace under the granted capabilities by setting the inheritable set), or (b) updatedocs/linux-security-features.mdto state plainly that filesystem violation monitoring on Linux requires running fence as root, and that thesetcap cap_bpf+ep fencerecipe only enables... (nothing observable today).Enabling eBPF Monitoring) so it doesn't promise a working rootless path, and note the--linux-features"CAP_BPF available" status is misleading because it checks fence's own caps, not thebpftracechild's ability to run.bpftracedependency with an in-process eBPF tracepoint program (fence already uses libbpf-style BPF for its seccomp filter), which would makeCAP_BPFon the fence binary actually sufficient.Notes
[fence:http]/[fence:socks]) log fine without root; only filesystem/syscall violations are affected.--linux-featurescurrently reportseBPF monitor ... ok (CAP_BPF available)even when this failure will occur, since it checks the fence process's own capabilities rather than end-to-end monitor viability.