~2,000 words · Reading time: 8 min · Series: eBPF: From Kernel to Cloud, Episode 2 of 18
In Episode 1, we established what eBPF is and why it gives Linux admins and DevOps engineers kernel-level visibility without sidecars or code changes. The obvious follow-up question is the one every experienced engineer should ask before running anything in kernel space:
Is it actually safe to run on production nodes?
The answer is yes — and the reason is one specific component of the Linux kernel called the BPF verifier. This post explains what the verifier is, what it protects your cluster from, and why it changes the risk calculus for eBPF-based tools entirely.
The Fear That Holds Most Teams Back
When I first explain eBPF to Linux admins and DevOps engineers, the reaction is almost always the same:
“So it runs code inside the kernel? On our production nodes? That sounds like a disaster waiting to happen.”
It is a completely reasonable concern. The Linux kernel is not a place where mistakes are tolerated. A buggy kernel module can take down a server instantly — no warning, no graceful shutdown, just a hard panic and a 3 AM phone call.
I know this from personal experience. During 2012–2014, I worked briefly with Linux device driver code. That period taught me one thing clearly: kernel space does not forgive careless code.
So when people started talking about running programs inside the kernel via eBPF, my instinct was scepticism too. Then I understood the BPF verifier. And everything changed.
What the Verifier Actually Is
Think of the BPF verifier as a strict safety gate that sits between your eBPF program and the kernel. Before your eBPF program is allowed to run — before it touches a single system call, network packet, or container event — the verifier reads through every line of it and asks one question:
“Could this program crash or compromise the kernel?”
If the answer is yes, or even maybe, the program is rejected. It does not load. Your cluster stays safe. If the answer is a provable no, the program loads and runs.
This is not a runtime check that catches problems after the fact. It is a load-time guarantee — the kernel proves the program is safe before it ever executes. Here is what that looks like when you deploy Cilium:
You run: kubectl apply -f cilium-daemonset.yaml
└─► Cilium loads its eBPF programs onto each node
└─► Kernel verifier checks every program
├─► SAFE → program loads, starts observing
└─► UNSAFE → rejected, cluster untouched
This is why Cilium can replace kube-proxy on your nodes, why Falco can watch every syscall in every container, and why Tetragon can enforce security policy at the kernel level — all without putting your cluster at risk.
What the Verifier Protects You From
You do not need to know how the verifier works internally. What matters is what it prevents — and why each protection matters specifically in Kubernetes environments.
Infinite loops
An eBPF program that never terminates would freeze the kernel event it is attached to — potentially hanging every container on that node. The verifier rejects any program it cannot prove will finish executing within a bounded number of instructions.
Why this matters: Every eBPF-based tool on your K8s nodes — Cilium, Falco, Tetragon, Hubble — was verified to terminate correctly on every code path before it shipped. You are not trusting the vendor’s claim. The kernel enforced it.
Memory safety violations
An eBPF program cannot read or write memory outside the boundaries it is explicitly granted. No reaching into another container’s memory space. No accessing kernel data structures it was not given permission to touch.
Why this matters: This is the property that makes eBPF safe for multi-tenant clusters. A Falco rule monitoring one namespace cannot accidentally read data from another namespace’s containers. The verifier makes this impossible at the program level, not just at the policy level.
Kernel crashes
The verifier checks that every pointer is valid before it is dereferenced, that every function call uses correct arguments, and that the program cannot corrupt kernel data structures. Programs that could cause a kernel panic are rejected before they load.
Why this matters: Running Cilium or Tetragon on a production node is not the same risk as loading an untested kernel module. The verifier has already proven these programs cannot crash your nodes — before they ever ran on your infrastructure.
Privilege escalation and kernel pointer leaks
eBPF programs cannot leak kernel memory addresses to userspace. This closes a class of container escape and privilege escalation attacks that have historically been possible through kernel module vulnerabilities.
Why this matters: Security tools built on eBPF — like Tetragon, which detects and blocks container escape attempts in real time — are not themselves a vector for the attacks they protect against.
eBPF vs Traditional Observability Agents
To appreciate what the verifier gives you operationally, compare the two main approaches to K8s observability.
Traditional agent — DaemonSet sidecar approach
Your K8s cluster
└─► Node
├─► App Pod (your service)
├─► Sidecar container (injected into every pod)
│ └─► Reads /proc, intercepts syscalls via ptrace
│ └─► 15–30% CPU/memory overhead per pod
└─► Agent DaemonSet Pod
└─► Aggregates data from all sidecars
Problems with this model:
- Sidecar injection requires modifying every pod spec and typically an admission webhook
- ptrace-based interception adds 50–100% overhead to the traced process and is blocked in hardened containers
- The agent runs in userspace with elevated privileges — a larger attack surface
- Updating the agent requires pod restarts across your fleet
eBPF-based tool — Cilium / Falco / Tetragon
Your K8s cluster
└─► Node
├─► App Pod (your service — completely unmodified)
├─► App Pod (another service — also unmodified)
└─► eBPF programs (inside the kernel, verifier-checked)
└─► See every syscall, network packet, file access
└─► Forward events to userspace agent via ring buffer
Benefits:
- No sidecar injection — pod specs stay clean, no admission webhook required
- Kernel-level visibility with near-zero overhead (typically 1–3%)
- The verifier guarantees the eBPF programs cannot harm your nodes
- Works identically with Docker, containerd, and CRI-O
Tools You Are Probably Already Running — All Verifier-Protected
You may already be running eBPF on your nodes without thinking about it explicitly. In each case below, the verifier ran before the tool ever touched your cluster.
| Tool | How the verifier is involved |
|---|---|
| Cilium | Every network policy decision, service load-balancing operation, and Hubble flow log is handled by eBPF programs that passed the verifier at node startup. |
| Falco | Every Falco rule is enforced by a verifier-checked eBPF program attached to syscall hooks. Sub-millisecond detection is only possible because the program runs in kernel space. |
| AWS VPC CNI | On EKS, networking operations have progressively moved to eBPF for performance at scale. If you are on a recent EKS AMI, eBPF is already doing work on your nodes. |
| systemd | Modern systemd uses eBPF for cgroup-based resource accounting and network traffic control. Active on most current Ubuntu, RHEL, and Amazon Linux 2023 installations. |
Questions to Ask When Evaluating eBPF Tools
When a vendor tells you their tool uses eBPF, these three questions will quickly tell you how mature their implementation is.
1. What kernel version do you require?
The verifier’s capabilities have expanded significantly across kernel versions. Tools targeting kernel 5.8+ can use more powerful features safely. Tools claiming to work on kernel 4.x are constrained by an older, more limited verifier.
- EKS: Amazon Linux 2023 and recent Ubuntu EKS-optimised AMIs fully support the modern eBPF feature set.
- GKE / AKS: Check the node OS kernel version — most managed K8s offerings on recent node images are eBPF-ready.
2. Do you use CO-RE?
CO-RE (Compile Once, Run Everywhere) means the tool’s eBPF programs work correctly across different kernel versions without recompilation. Tools using CO-RE are more portable and significantly less likely to break after a routine node OS update. This is a reliable signal of engineering maturity in the vendor’s eBPF implementation.
3. What eBPF program types do you use?
Different program types have different privilege levels and access scopes. A tool that only needs kprobe access is asking for considerably less privilege than one requiring lsm hooks.
kprobe/tracepoint— observability and debuggingtc(traffic control) — network policy enforcementxdp(eXpress Data Path) — high-performance packet processinglsm(Linux Security Module) — security policy enforcement (used by Tetragon)
Understanding the program type tells you what the tool can and cannot see on your nodes, and how much kernel access you are granting it.
How Falco Uses the Verifier — A Step-by-Step Walkthrough
Here is exactly what happens when Falco starts on one of your K8s nodes, and where the verifier fits in:
1. Falco pod starts on the node (via DaemonSet)
2. Falco loads its eBPF programs into the kernel:
└─► BPF verifier checks each program
├─► Can it crash the kernel? No → continue
├─► Can it loop forever? No → continue
├─► Can it access out-of-bounds memory? No → continue
└─► PASS → program loads
3. Falco's eBPF programs attach to syscall hooks:
└─► sys_enter_execve (every process execution in every container)
└─► sys_enter_openat (every file open)
└─► sys_enter_connect (every outbound network connection)
4. A container runs an unexpected shell (potential attack):
└─► execve() called inside the container
└─► Falco's eBPF hook fires in kernel space
└─► Event forwarded to Falco userspace via ring buffer
└─► Falco rule matches: "shell spawned in container"
└─► Alert fired in under 1 millisecond
5. Your container, your other pods, your node: completely unaffected
Step 2 is what the verifier makes safe. Without it, attaching eBPF hooks to every syscall on your production node would be an unacceptable risk. With it, Falco can offer this level of visibility with a mathematical safety guarantee.
The Bottom Line
You do not need to understand BPF bytecode, register states, or static analysis to use eBPF tools safely in production. What you do need to understand is this:
The BPF verifier is the reason eBPF is fundamentally different from kernel modules. It does not just make eBPF “safer” in a vague sense — it provides a mathematical proof that each program cannot crash your kernel before that program ever runs.
This is why eBPF-based tools can deliver deep kernel-level visibility into every container, every syscall, and every network flow — with near-zero overhead, no sidecar injection, and production safety that kernel modules could never guarantee.
The next time someone on your team hesitates about running Cilium, Falco, or Tetragon on production nodes because “it runs code in the kernel” — you now know what to tell them. The verifier already checked it. Before it ever touched your cluster.
Further Reading
- Cilium documentation: eBPF and the Linux kernel
- Falco: eBPF probe documentation
- Tetragon: eBPF-based security observability
- The official eBPF website: ebpf.io
Questions or corrections? Reach me on LinkedIn. If this was useful, the full series index is on linuxcent.com — search the eBPF Series tag for all episodes.
)
)

