For a long time, "deep" Linux security tooling meant kernel modules: powerful but invasive, version-fragile, and a real risk if they crashed. eBPF changed that. It lets you run small, verified programs inside the kernel at well-defined hook points — system calls, network events, scheduler events, tracepoints — without writing a kernel module, and without compromising stability. Almost every modern Linux runtime security tool (Falco, Tetragon, Cilium, Pixie, Datadog, Sysdig, many EDR products) is built on eBPF underneath. Understanding what it does and what it doesn't do helps you evaluate tooling and write better detections.
What eBPF actually is
eBPF (the "e" originally stood for "extended", from the older Berkeley Packet Filter used by tcpdump) is a small virtual machine inside the Linux kernel. You write a program — typically in restricted C, Rust, or via a higher-level DSL — compile it to eBPF bytecode, and load it. Before the kernel runs it, a verifier checks that the program will terminate, does not dereference invalid pointers, does not loop unboundedly, and only touches data it is allowed to. If verification passes, the program is JIT-compiled and attached to a hook.
Key properties that matter for security:
- Safety by verification – A bug in your eBPF program cannot panic the kernel. The worst it can do is be rejected at load time. This is fundamentally different from kernel modules.
- High performance – eBPF programs run in the kernel, near the events they observe, with no context switches per event. Throughput is high enough to inspect every system call on a busy host.
- Rich hook points – kprobes, kretprobes, uprobes (user-space functions), tracepoints, LSM (Linux Security Module) hooks, network points (XDP, tc), and perf events. You can observe almost anything the kernel does.
- Maps for communication – eBPF programs share state with user-space tools via "maps" (ring buffers, hash maps, arrays). A user-space agent reads events from the ring buffer and turns them into alerts or logs.
- Kernel version dependence is shrinking – BPF CO-RE (Compile Once, Run Everywhere) and libbpf mean modern eBPF programs work across a wide range of kernels without recompilation.
eBPF is not magic; it cannot see things the kernel itself cannot see, and it cannot bypass mandatory access control. But it does give defenders a vantage point that previously required vendor kernel modules.
What eBPF gives security teams
Three broad categories of capability matter for security.
- Runtime visibility – Process execution with full command lines, parent-child trees, file opens, network connections, DNS queries, capability use, and kernel calls. The same telemetry many EDR products charge handsomely for, available as a structured event stream.
- Network observability – L3–L7 visibility (IP, TCP, HTTP, DNS, TLS handshake metadata, gRPC) without spanning ports or installing inline proxies. Service-mesh-class data on every node.
- Active enforcement – Some eBPF hooks (LSM, certain network hooks) can block as well as observe. Tetragon can kill processes that violate a policy; Cilium can drop packets that match a rule. This is where eBPF crosses from observability into runtime protection.
For most security teams, the immediate value is the first one: a per-host stream of high-fidelity events that is cheap to collect and easy to filter, without deploying yet another kernel module.
Tooling: Falco, Tetragon, Cilium, and the BCC family
Several mature open-source projects are worth knowing.
- Falco – The most established eBPF-based runtime detection tool, originally from Sysdig and now a CNCF graduated project. Ships with a rules engine ("detect when a shell is spawned inside a container", "detect a write to
/etc/shadow", "detect a process making a network connection outside its allowlist") and integrates with most alerting backends. - Tetragon – From the Cilium project (Isovalent). Goes further than Falco by adding enforcement: not just "detect a process executing", but "kill any process whose binary path doesn't match policy". Heavy use of BPF LSM hooks.
- Cilium – Primarily a Kubernetes CNI plugin, but a huge amount of its value is security: network policies enforced in eBPF, identity-aware policies tied to Kubernetes labels, transparent mTLS via WireGuard or IPsec, and Hubble for L7 observability.
- bcc and bpftrace – The "BPF Compiler Collection" gives you Python wrappers and a huge collection of ready-made tools (
execsnoop,tcpconnect,opensnoop,bashreadline).bpftraceis adtrace-like scripting language for ad-hoc tracing. Both are gold for incident response on a host where you do not have a full security agent. - Pixie – Auto-instruments Kubernetes workloads with eBPF for application-layer observability (HTTP, MySQL, Redis), with a security angle for spotting unusual API behaviour.
Commercial EDR vendors increasingly use eBPF under the hood on Linux too, so the underlying technology is the same; the differences are in rule content, management, and integration.
Writing a useful detection: a worked example
A common Falco rule, conceptually, looks something like:
- Trigger – A process executes whose binary path is
/bin/sh,/bin/bash, or another shell. - Context – Its parent process is one of
nginx,apache2,php-fpm, ornode, AND the host is inside aproductionnamespace label. - Negate – Unless the container image is one explicitly allowed to spawn shells (e.g. a maintenance image).
- Action – Emit an event with the full process tree, container name, image, namespace, and user; route to the SOC's alert queue.
This kind of rule is impractical with file-based log analysis (the event happens and is gone in microseconds) but trivial with eBPF, because the agent sees the execve system call directly. Similar patterns work for "unexpected outbound connection from a database pod", "write to a sensitive path that only a single binary should touch", "container modifying its own filesystem when it should be read-only", and "kernel module load on a server that does not load modules".
The general principle: describe behaviour in terms the kernel can observe (syscalls, processes, file paths, network endpoints, capabilities, namespaces), and let the agent translate that into events. Avoid string-matching on log output where you can match on the underlying event directly.
Operational considerations
eBPF tooling is well-behaved but not free. A few things to plan for.
- Kernel compatibility – Most modern tooling supports kernels from roughly 5.x onwards; some advanced features (BPF LSM, ring buffers, certain network hooks) require newer ones. Older long-term distros may need backported kernels.
- Event volume – Naively logging every
execveandconnecton a busy host produces gigabytes of data per day. Filter in-kernel (in the eBPF program itself), pre-aggregate, and ship only what is useful. The cheap collection is wasted if you bottleneck on the SIEM. - Privilege model – Loading eBPF programs requires
CAP_BPF(modern) or full root (older kernels), so the agent itself is high-privilege. Treat it as Tier 0 software: sign and verify the daemonset image, run it from a private registry, monitor changes to it, and patch promptly. - Performance overhead – Real-world overhead is usually a few percent of CPU on busy hosts, and negligible on quiet ones. Validate on representative workloads before rolling out fleet-wide.
- Coexistence – Multiple eBPF agents (EDR + Cilium + Falco) can co-exist but compete for hooks and CPU. Pick a small, deliberate set rather than installing everything.
- Auditability – Treat eBPF rule sets as code: stored in git, peer-reviewed, tested with adversary-emulation tooling, and rolled out gradually.
eBPF will not solve security on its own, but it has genuinely lowered the cost of high-quality runtime visibility on Linux. For most teams, the right move is to pilot Falco or Tetragon on a handful of hosts or a single Kubernetes cluster, write a small number of high-fidelity rules tied to ATT&CK techniques, and prove the value before expanding. Done that way, it gives you EDR-class signal without EDR-class cost — and a foundation for genuinely useful detection engineering.