Traditionally, two options existed for kernel-level work: read what the kernel
chose to expose, or write a kernel module and accept that a bug means a panic.
eBPF adds a third: load your own program into the running kernel, attach it to
an event, and trust that the kernel won’t let it crash anything. It’s the
technology under bpftrace, Cilium, and most of the new observability stack.
A Virtual Machine Inside the Kernel
eBPF is a small register-based virtual machine built into Linux. You compile a restricted C program to eBPF bytecode, load it, and the kernel runs it in a sandbox when a chosen event fires:
your .c ──clang──▶ eBPF bytecode ──load──▶ [ verifier ]
│ pass
▼
attached to an event, JIT-compiled,
runs in kernel contextIt is not a module. It can’t call arbitrary kernel functions, can’t loop unboundedly, and can’t touch memory it wasn’t handed.
The Verifier Is the Whole Trick
Before anything runs, the verifier statically analyzes every possible path through the program and rejects it unless it can prove safety:
- all loops bounded (no infinite loops)
- no out-of-bounds memory access
- no uninitialized reads
- bounded total instruction countThis is why eBPF is safe where modules aren’t: a program that might misbehave never loads. The cost is a constrained programming model — you write to please the verifier, which can be maddening, but it’s what makes running untrusted code in ring 0 acceptable.
Maps: Talking to User Space
An eBPF program is event-driven and short-lived, so it needs somewhere to keep state and a way to report results. Maps are kernel-resident key-value stores shared between the eBPF program and user space:
kernel: eBPF program ──writes──▶ [ map ] ◀──reads── user-space tool
(e.g. count syscalls) (hash, array, ring buffer, ...)Counters, histograms, per-PID stats — all live in maps. A user-space program polls them to draw the flame graph or latency histogram you actually see.
Where It Attaches
The power is the breadth of attach points:
kprobes / tracepoints → trace any kernel function or event
uprobes → trace user-space functions too
XDP → process packets at the NIC driver, pre-stack
tc / cgroup hooks → shape and filter traffic, enforce policy
LSM hooks → make security decisionsThe same mechanism powers bpftrace one-liners, Cilium’s networking, and runtime
security tools — one kernel feature, three industries.
# Count system calls by process, live, no kernel module:
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'Takeaways
- eBPF runs sandboxed programs inside the kernel, attached to events — a safe alternative to kernel modules.
- The verifier statically proves each program is bounded and memory-safe before it loads; that guarantee is the core of eBPF.
- Maps are shared key-value stores that pass state and results between kernel and user space.
- Broad attach points (kprobes, XDP, LSM) make one mechanism the basis of modern tracing, networking, and security tooling.