the eBPF verifier
Letting an outside program run inside the kernel sounds terrifying: one bad pointer or one infinite loop in kernel context could freeze or crash the entire machine. The eBPF verifier is the gatekeeper that makes it safe. Before the kernel will accept any eBPF program, the verifier examines it instruction by instruction and PROVES — mathematically, before the program ever runs — that it cannot do anything dangerous. If it cannot prove safety, the program is rejected outright.
How it works in plain steps: the verifier performs a static analysis that simulates every possible path through the program. It tracks, for every register at every instruction, the set of values it could hold, and it checks several properties. It proves the program always terminates — historically by forbidding loops entirely, and now by requiring any loop to have a verifiable bound, so there is no way to spin forever in the kernel. It proves every memory access is in bounds — every pointer dereference and every map access must be provably within a known, checked range, so there are no wild pointers. It proves the program only calls approved helper functions and respects their argument types. And it enforces a small stack and a limited number of instructions so the work is bounded. Only a program that passes all of this is handed to the just-in-time compiler and attached to its hook.
It matters because it is the reason eBPF can be exposed to less-privileged users at all and the reason production engineers trust running it on live machines: safety is established by proof, not by hoping the author was careful. The honest caveats are real and frequently felt. The verifier is conservative — it rejects many programs that are actually safe but that it cannot prove safe, which is why 'the verifier rejected my program' is the classic eBPF frustration. Its proof effort grows with program complexity, so large programs can hit limits. And it guards against memory-safety and termination faults — it is not a guarantee that your program's LOGIC is correct, only that it cannot crash or hang the kernel.
// rejected: the verifier cannot prove i stays in bounds for (int i = 0; i < n; i++) buf[i] = 0; // n is unknown -> 'unbounded loop' / 'possible OOB' // accepted: a compile-time bound it can prove #pragma unroll for (int i = 0; i < 64; i++) buf[i] = 0; // fixed, provable
The verifier accepts the bounded, provable loop and rejects the one whose bound it cannot establish — safety by proof, before any execution.
A frequent misconception: rejection does not mean your program is buggy. The verifier proves safety, and being conservative it also rejects many SAFE programs whose safety it merely cannot prove — much eBPF craft is rephrasing correct code so the verifier can follow it.