CONCEPT Cited by 2 sources
eBPF verifier¶
The eBPF verifier is the static-analysis pass the Linux kernel runs on every eBPF program before it's allowed to load. It proves that the program is safe to execute in kernel context: it terminates (no unbounded loops), respects memory bounds, doesn't read uninitialised memory, and stays within instruction / stack / complexity limits.
The verifier is simultaneously:
- eBPF's signature safety guarantee — the reason eBPF programs are deployable into production kernels where custom kernel modules are not.
- The last line of defence against eBPF-based kernel exploits (see CVE-2023-2163, CVE-2024-41003).
- The primary source of variability that makes eBPF operationally hard at fleet scale — what verifies on one kernel can fail to verify on another.
(Source: sources/2026-01-07-datadog-hardening-ebpf-for-runtime-security)
What the verifier checks¶
- Termination. No unbounded loops (bounded loops supported from later kernels; pre-bounded-loop kernels require manual unrolling).
- Memory bounds. Every pointer dereference must be provably within a known valid region. Stack variables occupy 8-byte-aligned "stack slots"; packing smaller variables can confuse the verifier.
- Instruction count. From 4,096 initially to 1 million from kernel 5.2 — programs exceeding this are rejected.
- Map operation legality. Some patterns restricted on older kernels (e.g. map-value as another map's key was unsupported before 4.18).
- Context + tail-call consistency. From 6.11 tail-call targets must match context type, not just program type.
- Helper availability. Context-dependent — Lockdown mode can
disable
bpf_probe_write_user,bpf_probe_read, etc.
Why it evolves¶
Every kernel release can add, tighten, or occasionally relax verifier rules. Datadog's Workload Protection supports kernels back to 4.15 (as of kernel 6.18 upstream) — verifier behaviour differs across that range in ways that routinely cause "works-in-dev, fails-in-prod" surprises.
Examples of subtle verifier drift (from the Datadog post):
- Dead-code elimination at load time (allowing constant-patched program logic) from 4.15 — pre-4.15 kernels need alternative logic paths for the same product feature.
- Instruction-count cap expansion (4k → 1M) reshapes what's expressible in-kernel.
- Tighter memory-bounds checks on modern kernels may force extra explicit bounds checks that older kernels didn't require.
- "Flaky" verifier failures when smaller-than-64-bit stack variables share an 8-byte slot.
Mitigation patterns¶
Datadog's Workload Protection handles verifier variability via:
- Comprehensive CI matrix — a kernel version/distro is only "supported" if it's actively tested.
- systems/ebpf-manager — centralised lifecycle library where verifier-quirk abstractions live (macros, wrappers).
- systems/co-re — handles layout drift without recompilation.
- Minimum-viable hook set —
ebpf-managerfails the product loudly if a critical program won't verify on this kernel rather than serving reduced coverage silently.
Why it forces patterns/two-stage-evaluation¶
The verifier's complexity limit caps how rich in-kernel rule logic can be. Sophisticated expressions (wildcards, cross-field correlation, stateful patterns) often don't fit — so the architecture becomes "cheap kernel pass → rich user-space pass" with a data contract via eBPF maps (patterns/approver-discarder-filter is the canonical fill for the kernel side in systems/datadog-workload-protection-fim).
Seen in¶
- sources/2025-11-18-datadog-ebpf-fim-filtering — cited as the reason full rule logic can't move into the kernel; motivates the approver/discarder split.
- sources/2026-01-07-datadog-hardening-ebpf-for-runtime-security — 5-year operational retrospective extensively documents verifier evolution as Lesson 1's centrepiece; lists specific kernel commits as milestones.