Follow
Subscribe via Email!

Enter your email address to subscribe to this platform and receive notifications of new posts by email.

Linux eBPF: How the In-Kernel Engine Runs Safe Code

Linux eBPF provides an in-kernel virtual machine that lets developers run sandboxed programs safely at runtime, enabling high-speed networking, telemetry, and security policies.
Official eBPF logo featuring a stylized bee mascot beside typography on a dark background.

The Linux kernel acts as the core bridge between physical hardware and user software, managing system memory, process scheduling, and network interfaces. Adding new features to this privileged space previously meant patching source code directly or inserting custom kernel modules. The introduction of Linux eBPF altered that path by allowing engineers to run sandboxed programs inside the operating system kernel at runtime [1]. Because these programs run when kernel events trigger, teams can safely observe and filter system activity without modifying the underlying operating system. Today, companies like Meta, Netflix, Google, Cloudflare, and Microsoft deploy Linux eBPF in live systems to handle high-speed packet filtering, security policy checks, and deep runtime tracing [1, 2].

What Is Linux eBPF?

Modern operating systems must deliver high throughput while preserving host stability against software faults. In earlier releases, tracing system events or filtering network traffic forced admins to insert kernel modules that risked crashing the entire machine if a pointer bug occurred [2]. The extended Berkeley Packet Filter expands packet filtering into safe kernel code [3]. Linus Torvalds praised that flexibility [2].

Linus Torvalds said that “BPF has actually been really useful, and the real power of it is how it allows people to do specialized code that isn’t enabled until asked for” [2]. The acronym BPF originally stood for Berkeley Packet Filter, but the modern subsystem is now treated as a standalone name because its scope extends far beyond basic packet capture. In Linux source code and documentation, developers use the terms BPF and eBPF interchangeably while calling the original engine classic BPF [1]. Community members created an official mascot named eBee, designed by Vadim Shchekoldin and confirmed during the first eBPF Summit [2]. It represents an open community where software teams collaborate on system observability and networking tools like Cilium, bpftrace, and bcc [1].

Engineering teams use Linux eBPF today to build monitoring tools, load balancers, and security telemetry agents that inspect millions of live requests each second [1]. Research by Vieira et al. (2020) showed that combining eBPF with the eXpress Data Path enables fast packet handling directly at the network interface driver level for platforms like Facebook and Cloudflare [14]. Netflix cloud instances run 15 BPF programs by default for system tracing. Facebook runs over 40 [4]. These tools run quietly in the background without disturbing user applications [1].

Linux eBPF system call hook diagram
System call hooks run bytecode routines when tasks request kernel services. (Credit: ebpf.io)

Origins of the Virtual Machine

The shift from classic BPF to eBPF turned a simple packet filter into an 11-register 64-bit virtual machine. Classic BPF relied on just two 32-bit registers, named A and X, alongside a hidden frame pointer. In contrast, the modern virtual machine provides ten general-purpose registers, numbered R0 through R9, plus one read-only frame pointer register stored in R10. The register width grew to 64 bits [3].

Each register is 64 bits wide and includes 32-bit lower subregisters that zero-extend into 64 bits when written by arithmetic logic units. Because 64-bit CPUs pass arguments via hardware registers, the virtual machine maps its registers directly to underlying CPU registers on x86_64 and arm64 architectures to avoid move steps. When an eBPF program begins, the kernel places the input context pointer into register R1. Registers R1 through R5 carry function arguments into in-kernel helper functions, while register R0 holds the function return value. After a helper call completes, registers R0 through R5 reset to an unreadable state, which forces the program to preserve important data in the callee-saved registers R6 through R9 [3].

Original instruction sets supported only basic two-operand math and conditional jumps [3]. Coders can compile C code into eBPF bytecode using LLVM, Clang, or GCC toolchains that emit optimized instructions [1]. The kernel implementation initially included 87 distinct instructions that mapped cleanly to physical machine instructions on x86_64 hardware. This direct register mapping lets the Just-In-Time compiler emit native hardware instructions without executing expensive register spill routines [3].

How the Verifier Enforces Safety

Understanding Linux eBPF execution starts with the verifier, because kernel safety represents the core rule for running uncompiled code in operating system space [1]. Before any program can attach to a kernel hook, it must pass through the in-kernel eBPF verifier, which performs static analysis to prove that execution cannot corrupt host memory or destabilize the system [2]. The verifier runs two distinct stages [3].

The verification process starts with a depth-first search across all program paths to ensure code flow cannot loop forever, followed by abstract interpretation of every instruction to track register state and stack bounds [2, 3]. The verification engine rejects any program that attempts out-of-bounds memory access, leaves variables uninitialized, or dereferences unchecked pointers [2]. To guarantee that programs terminate and release CPU resources, the verifier checks for bounded execution and prohibits infinite loops [1]. Early kernel designs placed a limit of 4096 instructions per program to bound verification complexity [3]. Over time, kernel contributors added support for bounded loops, function-by-function validation, and dead-code elimination while preserving the core termination guarantee [2].

Katran network forwarding plane architecture
Katran pairs XDP driver mode with in-kernel programs to steer traffic on backend hosts. (Credit: Engineering at Meta)

Privilege boundaries also govern who can load programs into the kernel. Unless unprivileged eBPF is enabled in kernel settings, only processes running with root privileges or holding the CAP_BPF capability can load bytecode [1]. Hung and Sani (2024) analyzed this subsystem while testing their BRF runtime fuzzer, pointing out that general fuzzers like Syzkaller often fail to test the eBPF runtime because the verifier firmly rejects malformed inputs and unsatisfied system call dependencies [17]. Passing verifier checks proves safety [1].

Tail Calls and Function Chaining

Complex applications often need more logic than can fit comfortably within a single verified routine. To solve this constraint, Linux provides tail calls, which let an executing program jump to another program without returning to the caller [9]. Unlike traditional subroutine calls, a tail call functions like a long jump [2].

Programs manage tail calls by reading from a program array map known as BPF_MAP_TYPE_PROG_ARRAY. The code invokes the bpf_tail_call helper function with a reference to the array and a target numeric index. To prevent accidental infinite loops, the Linux kernel enforces a hard limit of 32 consecutive tail calls per event invocation, allowing a total of 33 programs to execute in sequence. Each target program passes verification independently with its own complexity budget [9].

Combining tail calls with BPF-to-BPF function calls needs careful stack accounting. A standard program possesses a 512-byte stack frame, but when BPF-to-BPF calls mix with tail calls, the kernel shrinks the caller stack limit to 256 bytes. This reduction prevents stack overflow by ensuring the maximum combined stack depth across 32 tail calls cannot exceed 8k bytes [9]. Prior to Linux kernel 4.16 and LLVM 6.0, developers had to force inline function compilation, but modern toolchains permit natural function definitions that improve instruction cache efficiency [2]. Tail calls remain popular for updating packet processing rules dynamically without taking backend servers offline. Replacing or extending logic happens atomically while the system runs [9].

BPF CO-RE compilation and relocation workflow
BPF CO-RE relies on BTF metadata and libbpf to handle kernel struct relocations. (Credit: docs.ebpf.io)

Linux eBPF Networking with Katran

In network engineering, Linux eBPF pairs with driver-level hooks to deliver high-throughput packet inspection [1]. Standard network packet processing requires traversing the complete Linux network stack, including socket buffers, firewall rules, and routing tables, which consumes notable CPU cycles under heavy traffic. By pairing eBPF with the eXpress Data Path, engineers bypass those bottlenecks [6].

XDP allows packet handling routines to execute directly in network card driver space before the kernel allocates heavy socket buffer structures. Meta engineers Nikita Shirokov and Ranjeeth Dasineni released Katran, an open-source software Layer 4 load balancer that powers network traffic distribution across Facebook data centers and points of presence. Earlier load balancing infrastructure relied on the IPVS kernel module, which proved too CPU-intensive to run on the same machines as backend services. Katran solved this co-location problem by running an XDP-based forwarding routine that inspects packets upon arrival and forwards them using IP-in-IP encapsulation directly to backend application servers. Katran runs on commodity Linux servers [6].

Katran announces virtual IP addresses to internet switches using ExaBGP, which relies on equal-cost multipath routing to spread incoming packets across server pools. To select a backend server without state synchronization, Katran computes an extended Maglev consistent hash over the packet 5-tuple. The software maintains a local lookup table backed by an LRU cache. If memory pressure peaks, Katran can switch into a compute-only mode that calculates hashes on the fly. Because XDP runs lockless routines in parallel across receive queues, packet processing throughput scales linearly with the number of network interface queues [6].

Kernel event hook points overview
Predefined hooks let event-driven programs attach to network sockets and tracepoints. (Credit: ebpf.io)

BPF CO-RE and Kernel Portability

Maintaining compatibility across different Linux distributions and kernel versions posed a major hurdle during early eBPF deployments. Because eBPF programs read internal kernel structures, any change in struct field offsets or member names between kernel versions could break compiled bytecode. To eliminate recompilation hurdles, the community developed BPF CO-RE [10].

The CO-RE architecture unites three key technologies: BPF Type Format metadata, compiler relocation extensions, and the libbpf loader library. Kernel builds that enable BTF expose complete type and structure layouts through /sys/kernel/btf/vmlinux, allowing developers to generate a single vmlinux.h header file using the bpftool utility. Clang generates high-level relocation records inside the compiled ELF object file, describing exactly which struct fields the program intends to read [10].

When an application starts, libbpf inspects target kernel BTF information and dynamically patches field offsets before passing bytecode to the kernel verifier. This loader adaptation lets a single compiled binary run across diverse kernel versions without needing kernel development headers installed on host machines [10]. Tools like Cloudflare’s tubular rely on libbpf and pinned BPF maps in /sys/fs/bpf to manage dynamic socket routing rules across thousands of production edge servers without incurring service interruptions. The tubular tool inspects connections quickly [7]. The technology has shifted how teams deploy software inside modern kernel development workflows. Examples of libbpf loaders are cataloged in GitHub repositories like libbpf-bootstrap [10].

Linux eBPF Security with LSM Hooks

Deploying Linux eBPF security programs gives administrators granular control over operating system events. Historically, Linux administrators configured complex Mandatory Access Control frameworks such as SELinux or AppArmor, or wrote custom kernel modules to block risky operations. Linux 5.7 introduced a third option by allowing eBPF programs to attach to Linux Security Module hooks [8].

The BPF LSM framework lets security teams write fine-grained security policies in C that the kernel validates and attaches dynamically. Cloudflare used this capability to block privilege escalation attacks that exploit the unshare system call to create unauthorized user namespaces. By attaching a program to the cred_prepare LSM hook on kernel version 5.15, Cloudflare denied unprivileged namespace cloning while allowing root processes to proceed. Tracing with ftrace revealed that unshare execution consumed 63,294 CPU cycles without the policy and 70,138 cycles with the BPF hook, representing an acceptable 10% penalty for proactive kernel protection. Such access policies can complement security audits for modern OverlayFS filesystem patches. Cloudflare blocked unprivileged callers immediately [8].

Google engineer KP Singh introduced BPF LSM patches to unify runtime security telemetry with active policy enforcement. The patchset added the BPF_PROG_TYPE_LSM program type, using BPF trampolines to attach programs to security hooks without overhead [11]. In August 2021, technology leaders including Meta, Google, Isovalent, Microsoft, and Netflix formed the eBPF Foundation to support this open ecosystem, later joined by Red Hat, Huawei, Crowdstrike, Tigera, and Datoms [2]. Dave Thaler and Poorna Gaddehosur announced Microsoft’s ebpf-for-windows project, using the PREVAIL static verifier and uBPF to bring compatible APIs to Windows 10 and Windows Server 2016 [13].

Performance Tradeoffs in Production

Production evaluations of Linux eBPF highlight important architectural tradeoffs that engineering teams must evaluate carefully. Recent academic benchmarking by Shahinfar et al. (2025) showed that not all networked applications automatically benefit from in-kernel offloading. In certain high-throughput scenarios, running packet processing inside kernel context can cause performance isolation violations [18].

These isolation issues occur between colocated workloads, limiting the deployment density of host applications. Engineers should benchmark their specific traffic profiles rather than assuming in-kernel execution is universally faster [18]. Memory access patterns and state handling require tailored data structures to maintain peak speed. Research on network measurement sketches by Miano et al. (2023) showed that user-space networking algorithms like NitroSketch cannot be applied directly to eBPF without adaptation. By redesigning the sketching logic to fit eBPF’s low memory footprint and register constraints, the authors improved traffic measurement performance by 40% [15]. Similarly, Jadin et al. (2022) created the TCP Path Changer to make Linux TCP path-aware, rerouting connections around network congestion [19].

Tooling and ecosystem maturity continue to advance through frameworks like Polycube, which brings network function virtualization chains into kernel space [16]. Long-term maintainers like Daniel Borkmann have expanded programmable classifier support in cls_bpf, establishing standard primitives for container networking in Kubernetes [5, 12]. Brendan Gregg received the USENIX LISA Award for his systems performance methodologies, which established flame graphs and BPF tracing tools as industry standards for troubleshooting production software [4]. Enterprise deployments across Android, Samsung Galaxy, and Dropbox confirm that Linux eBPF remains central to operating system observability [2].

Sources
  1. WEBSITE ebpf.io. (2026). What is eBPF? An Introduction and Deep Dive into the eBPF Technology. [Article Link]
  2. WEBSITE Wikipedia. EBPF. [Article Link]
  3. WEBSITE Linux Kernel Documentation. Classic BPF vs eBPF. [Article Link]
  4. CONFERENCE PAPER Gregg, B. (2021). BPF Internals. USENIX Association. [Article Link]
  5. CONFERENCE PAPER Borkmann, D. (2020). eBPF and Kubernetes: Little Helper Minions for Scaling Microservices. KubeCon + CloudNativeCon Europe 2020. [Article Link]
  6. WEBSITE Shirokov, N., Dasineni, R., & Changigi. (2018). Open-sourcing Katran, a scalable network load balancer. Engineering at Meta. [Article Link]
  7. WEBSITE Cloudflare Blog. (2022). Production ready eBPF, or how we fixed the BSD socket API. [Article Link]
  8. WEBSITE Cloudflare Blog. (2022). Live-patching security vulnerabilities inside the Linux kernel with eBPF Linux Security Module. [Article Link]
  9. WEBSITE docs.ebpf.io. (2025). Tail calls. [Article Link]
  10. WEBSITE docs.ebpf.io. (2024). BPF CO-RE. [Article Link]
  11. WEBSITE Singh, K. P. (2020). MAC and Audit policy using eBPF (KRSI). Linux BPF Mailing List. [Article Link]
  12. WEBSITE Borkmann, D. (2015). eBPF support for cls_bpf. Linux Netdev Mailing List. [Article Link]
  13. WEBSITE Thaler, D., & Gaddehosur, P. (2021). Making eBPF work on Windows. Microsoft Open Source Blog. [Article Link]
  14. ACADEMIC JOURNAL Vieira, M. A. M., Castanho, M. S., Pacífico, R. D. G., Santos, É. R. S., Júnior, E. P. M. C., & Vieira, L. F. M. (2020). Fast Packet Processing with eBPF and XDP. ACM Computing Surveys, 53(1), 1-36. [Article Link]
  15. ACADEMIC JOURNAL Miano, S., Chen, X., Basat, R. B., & Antichi, G. (2023). Fast In-kernel Traffic Sketching in eBPF. ACM SIGCOMM Computer Communication Review, 53(1), 3-13. [Article Link]
  16. ACADEMIC JOURNAL Miano, S., Risso, F., Bernal, M. V., Bertrone, M., & Lu, Y. (2021). A Framework for eBPF-Based Network Functions in an Era of Microservices. IEEE Transactions on Network and Service Management, 18(1), 133-151. [Article Link]
  17. ACADEMIC JOURNAL Hung, H., & Sani, A. A. (2024). BRF: Fuzzing the eBPF Runtime. Proceedings of the ACM on Software Engineering, 1(FSE), 1152-1171. [Article Link]
  18. ACADEMIC JOURNAL Shahinfar, F., Miano, S., Panda, A., & Antichi, G. (2025). Demystifying Performance of eBPF Network Applications. Proceedings of the ACM on Networking, 3(CoNEXT3), 1-21. [Article Link]
  19. ACADEMIC JOURNAL Jadin, M., Coninck, Q. D., Navarre, L., Schapira, M., & Bonaventure, O. (2022). Leveraging eBPF to Make TCP Path-Aware. IEEE Transactions on Network and Service Management, 19(3), 2827-2838. [Article Link]
Leave a Comment

Related Posts
Total
0
Share