Skip to content

feat(build): Package Fibratus for Linux and complete the CLI surface - #738

Merged
rabbitstack merged 4 commits into
rabbitstack:linux-portfrom
mostafa:feat/linux-packaging
Sep 23, 2026
Merged

rabbitstack merged 4 commits into
rabbitstack:linux-portfrom
mostafa:feat/linux-packaging

Conversation

@mostafa

@mostafa mostafa commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Completes the Linux port: distribution packages, a service unit, the command surface an operator uses to inspect a running sensor, and install docs.

Packaging

make pkg produces a deb and an rpm through nfpm. Both carry the binary, a Linux configuration, the shipped rules, and the service unit. Nothing else needs packaging, because bpf2go embeds the BPF objects in the binary, so an install pulls in no compiler and no kernel headers.

Path Contents
/usr/bin/fibratus binary
/etc/fibratus/fibratus.yml configuration, `config
/etc/fibratus/rules/, rules/macros/ shipped rules
/lib/systemd/system/fibratus.service unit, /usr/lib/... on RPM distributions

Verified by installing rather than by building: the deb on Ubuntu 24.04 and the rpm on Rocky 9, checking the installed layout, that the binary runs, that fibratus rules validate passes against the installed configuration, and that systemd-analyze verify accepts the unit. CI builds both and uploads them.

The shipped configuration leaves out the Windows-only sections rather than carrying them inert, so what is in the file is what the platform actually reads.

Service unit

The unit starts as root on purpose. Attaching a syscall tracepoint reads its id from /sys/kernel/tracing, which is root-only on stock distributions, so a dedicated user would need tracefs loosened first. What constrains the process is the bounding set, which drops everything except:

  • CAP_BPF to load programs and maps
  • CAP_PERFMON to attach to tracepoints
  • CAP_SYS_PTRACE to read other users' /proc/<pid>/exe and cmdline
  • CAP_KILL, needed only when a rule uses the kill action

Two hardening choices are deliberate and commented in the unit. ProtectSystem=full rather than strict, because strict also mounts /run read-only and the API socket lives there. And ProtectProc=default, because hiding other processes would silently empty ps.exe and ps.cmdline instead of failing visibly.

API transport default

The shared default bound the API to localhost:8080, so a Linux install listened on the network before anyone asked it to. It now defaults to unix:///var/run/fibratus.sock, leaving reachability to socket permissions; a TCP address still works when set explicitly. Windows keeps its existing default through the same platform hook the config file and rule paths already use.

Stats

The Linux Stats struct was an empty placeholder, so fibratus stats rendered a table with no rows while the sensor published a dozen counters. It now carries the capture counters, the two drop counters worth alerting on, the startup handover, and the rule engine, ordered the way they are useful to read.

Coverage

  • Both transports, socket and TCP, against the endpoints fibratus config and fibratus stats actually call, plus a socket left behind by an unclean shutdown, which would otherwise need manual cleanup before a restart.
  • A privileged test drives that same path against a live capture and asserts every counter the stats table renders is published, since a unit test can only show the counters exist, not that a running sensor moves them.
  • Linux configuration defaults, including the transport.

make test, lint, GOOS=windows go build ./..., and the documented quick-start commands run against the installed package.

The shared default bound the API to localhost:8080, so a Linux install
listened on the network before anyone asked it to. Defaulting to a
socket under /var/run leaves reachability to filesystem permissions, and
a TCP address still works when it is set explicitly.

Windows keeps its existing default through the same platform hook the
config file and rule paths already use.
Comment thread build/linux/nfpm.yaml
Comment thread build/linux/nfpm.yaml Outdated
Comment thread build/linux/nfpm.yaml Outdated
Comment thread build/linux/nfpm.yaml Outdated
Comment thread build/linux/nfpm.yaml Outdated
Comment thread build/linux/nfpm.yaml Outdated
Comment thread build/linux/fibratus.service Outdated
Comment thread build/linux/fibratus.service
Ships the binary, a Linux configuration, the rules, and a service unit.
The BPF objects need no separate packaging because bpf2go embeds them in
the binary.

The unit starts as root, since attaching a syscall tracepoint reads its
id from /sys/kernel/tracing and that is root-only on stock kernels. What
constrains it is the bounding set, which drops everything except loading
programs, attaching to tracepoints, reading other users' procfs entries,
and signalling a target for the kill action. ProtectSystem is full
rather than strict because strict also mounts /run read-only and the API
socket lives there, and ProtectProc stays permissive because hiding
other processes would silently empty ps.exe and ps.cmdline.

The shipped configuration omits the Windows-only sections instead of
carrying them inert, so what is in the file is what the platform reads.
The Linux Stats struct was an empty placeholder, so the command rendered
a table with no rows against a sensor that publishes a dozen counters.
It now carries the capture, drop, startup handover, and rule engine
expvars, grouped in the order they are useful to read.

Covers the endpoints the config and stats commands call over a socket
and over TCP, including a socket left behind by an unclean shutdown,
which would otherwise need manual cleanup before a restart. The
privileged test drives the same path against a live capture, since unit
tests can only prove the counters exist, not that a running sensor moves
them.
Covers the package layout, running in the foreground against a filter,
and the service. Notes that an idle host with rules enabled is expected
to be quiet, since only matching events reach the outputs and silence
otherwise reads as a broken install.

Records why the unit runs as root and what the bounding set leaves it.
@mostafa
mostafa force-pushed the feat/linux-packaging branch from 8270866 to 318ee22 Compare September 23, 2026 18:12
@rabbitstack
rabbitstack merged commit 11bff87 into rabbitstack:linux-port Sep 23, 2026
1 check passed
@mostafa
mostafa deleted the feat/linux-packaging branch September 23, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants