Bringing Kernel-Deep Diagnostics to Linux: ET Ducky on eBPF
For the first year of ET Ducky, the agent was Windows-only, with ETW kernel-level event tracing as the sole basis for troubleshooting.
In pursuit of an expanding support base we explored the options for similar insight in Linux and Mac. Due to controls architecture, Linux is easier. After considering the different options, we concluded that eBPF was going to provide the most low-level visibility in Linux.
Because eBPF provides kernel visibility, the user experience is mostly the same, but guided troubleshooting, RCA, and troubleshooting recommendations all intelligently adapt to the operating system of the agent that is being viewed.
What ETW is to Windows, eBPF is to Linux
The Windows kernel exposes hundreds of ETW providers. Subscribe to a kernel-process provider and you see every NtCreateProcess with the parent PID, image path, command line, and a microsecond timestamp. Subscribe to disk I/O and you see every IRP_MJ_READ with the file path and the latency. The data is structured, kernel-clocked, and there whether or not anyone is watching.
Linux does not have ETW providers, but the Linux kernel has tracepoints, kprobes, and uprobes. eBPF programs attach to those points and run in a verified, sandboxed VM inside the kernel. The information they can extract is the same kind of structured kernel-clocked data: process exec with the parent PID and command line, file open with the path, network connect with the destination address and port. The verifier guarantees the program terminates, does not crash the kernel, and only reads memory it is allowed to read.
ET Ducky's Linux agent compiles a small set of eBPF programs (under 600 lines of C total) attached to four tracepoints:
sched_process_execandsched_process_exit, for the process lifecyclesys_enter_openatandsys_enter_close, for the file event streamsys_enter_connect, for outbound network connectionssys_exit_accept4, for inbound accepts
These are the four diagnostic axes that matter most for the kinds of problems operators bring to an RMM: what process is doing the thing, what file or path the thing happens to, what network endpoint is involved, and how long it took. We add tracepoints when the diagnostic value is clear and we leave them off when it is not.
CO-RE, BTFHub, and a single binary
One of the practical reasons eBPF was historically hard to ship across the fleet is that kernel data structures change between versions. A program built against the type definitions of one kernel will read garbage when run against another. The traditional workaround was to compile per-host, which is unworkable for an RMM agent.
The ecosystem solved this with CO-RE (compile once, run everywhere). The agent's eBPF programs are built against generic field accessors, and the kernel's BTF (BPF Type Format) data is consulted at load time to relocate every field reference to the right offset for the running kernel. On any kernel that exposes /sys/kernel/btf/vmlinux, the same agent binary works without source changes.
Older kernels (RHEL 7, Ubuntu 16.04 long-term-support, certain locked-down kernel builds) do not ship BTF. For those, the agent falls back to BTFHub - a community-maintained collection of BTF data for kernels that did not have it natively. The agent ships a small subset of BTFHub data alongside the binary and uses it transparently when the local kernel does not expose its own.
If even that fails (very old kernels, very locked-down embedded builds), the agent runs in a graceful no-op mode. Health metrics still ship, hardware health still ships, the live-session AI flow still works. Only the kernel-event capture is degraded. That is the right failure mode for an RMM agent: keep the rest of the product alive and tell the operator what is missing.
Same wire format, same dashboard
The eBPF programs emit a packed binary structure into a per-CPU ring buffer. A small piece of agent code reads from the buffer, normalises each event into the same SystemEvent shape the Windows agent uses, and feeds it into the same downstream pipeline: the recent-events cache, the inflection bracketing path, the behavioral rule engine, the live-session prompt builder.
That is the property that matters. There is no "Linux agent" branch in the dashboard, no "Linux mode" in the AI prompt, no separate query language for Linux fleets. A query that asks "show me the top memory hogs across the fleet" runs against both Windows and Linux rows. A behavioral rule that watches for a shell launching a downloader fires on either OS from the same definition. The cross-OS columns that exist (BitLocker is Windows-only; ClamAV is Linux-specific) are filtered automatically by the smart-report planner so a question about disk encryption does not return null rows for half the fleet.
The unprivileged agent on Linux
The Linux agent runs as the unprivileged etducky user under a hardened systemd unit, with cgroup limits on CPU, memory, and task count. It does not have CAP_SYS_ADMIN; it has the narrower set of capabilities eBPF actually needs (CAP_BPF, CAP_PERFMON) plus the few that operator-elevated commands require (and only because of how sudo -S is structured under the hood).
The cgroup ceilings (512 MB memory, 50% CPU, 256 tasks) are not tight in practice. The eBPF capture path is rate-limited per-process inside the kernel programs themselves; under normal load the agent sits at single-digit megabytes of resident memory and trace-amount CPU. The bounds exist so a misbehaving agent cannot crowd out the workloads on the host. If an operator notices the agent is at 50% CPU for any sustained period, that is an agent bug, not a host problem.
This matters for the kinds of customers who care about agent footprint. A database server is happy to run an agent that uses 0.1% CPU and 50 MB of RAM. The same database server is not happy to run an agent that grew its cache unbounded after a kernel-event spike or a logging loop. The cgroup ceiling is the answer to "what's the worst case?"
What the Linux agent does today
For an RMM agent that is "telemetry-only in v1" (which is the design intent on the Linux side), the working feature set as of May 2026:
- Health metrics: CPU, memory, disk I/O, network, per-NIC breakdown, system info, distribution and kernel identity. Same DTOs as the Windows agent.
- Hardware health: thermal zones, battery state, optional SMART via
smartctl(opt-in at install). - Optional sub-objects on the heartbeat: top-N processes, disk space per mount, active user sessions (via
who), security posture (firewall via ufw/firewalld/nft, SecureBoot via efivars, ClamAV state). - Inflection detection: cross-platform rule that compares consecutive heartbeat snapshots and emits inflection records for CPU spikes, memory drops, disk-queue saturation, etc. Same detector class the Windows agent uses.
- eBPF kernel-event capture: process lifecycle, file open/close, network connect, network accept. Rate-limited per-process so a fork bomb cannot drown the stream.
- Live-session AI flow: shell exec, file push and pull, command output streaming. The agent runs unprivileged; privileged commands route through the operator-elevation flow described in the security whitepaper.
- Remote desktop: Wayland portal capture via xdg-desktop-portal and PipeWire, with x11vnc as an X11 fallback. Browser-side decode via WebCodecs when available.
- Behavioral security rule engine: cross-platform rules subscribing to the same eBPF event stream the diagnostic pipeline uses.
- Smart Reports: natural-language queries that pierce the Linux-specific JSON columns (
ProcessesJson,DiskSpaceJson,UserSessionsJson,SecurityPostureJson) the same way they pierce the Windows ones.
What is not on Linux yet, by design: ETW-style fine-grained user-mode provider taps (the Windows agent has 30+ user-mode providers; Linux's user-mode story does not have a one-to-one equivalent and we are not faking one), and the Windows-only behavioral monitor with automatic network isolation on encryption sweeps. The cross-platform behavioral rule engine catches earlier-stage indicators on Linux; the automatic-isolation tier is something we will add when the right Linux equivalent lands.
Why this matters in practice
If you are running a mixed Windows-and-Linux fleet, the market usually offers either (a) two RMMs, one for each OS, or (b) one RMM that "supports" Linux through a thin agent polling /proc and parsing top. The second option is functionally equivalent to WMI-polling RMMs - on Linux instead of Windows.
The point of the Linux agent is that it is not that. It is the same diagnostic depth on Linux as on Windows, the same dashboard, the same AI live sessions, the same behavioral rules, the same query language. eBPF on Linux fills the role ETW fills on Windows, and the rest of the product is exactly the rest of the product.
The companion post on this is Why Your RMM Tool Is Missing What ETW Can See. Everything in that post about the diagnostic gap on Windows applies on Linux with eBPF substituted for ETW.
Ready to try ET Ducky?
Deploy an agent in minutes. Same agent code on Windows and Linux.
Get Started Free