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:

text
   your .c  ──clang──▶  eBPF bytecode  ──load──▶  [ verifier ]
                                                       │ pass

                                     attached to an event, JIT-compiled,
                                     runs in kernel context

It 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:

text
   - all loops bounded (no infinite loops)
   - no out-of-bounds memory access
   - no uninitialized reads
   - bounded total instruction count

This 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:

text
   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:

text
   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 decisions

The same mechanism powers bpftrace one-liners, Cilium’s networking, and runtime security tools — one kernel feature, three industries.

bash
# 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.