Back to Blog

Bringing Kernel-Deep Diagnostics to Linux: ET Ducky on eBPF

Christopher 7 min read
linuxebpfdiagnosticskernel

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:

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:

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