Check out our latest blog: "eBPF Decoded: Use Cases, Concepts, and Architecture"

Learn More
logo

What is eBPF?

A Powerful Tool for Extending the Linux Kernel

eBPF, or extended Berkeley Packet Filter, is a revolutionary technology embedded within the Linux kernel. It allows developers to write and execute sandboxed programs directly in the kernel space, a privileged area traditionally off-limits for user-level modifications. This capability unlocks a new paradigm for extending the kernel's functionality without requiring changes to the kernel source code or loading additional modules.

Historically Complex Kernel Modifications

In the past, implementing features like security, networking, and observability directly within the kernel was considered ideal due to the kernel's privileged system access. However, modifying the kernel itself is a complex and cautious process. The kernel plays a critical role in system stability and security, so changes require rigorous testing and verification. This often leads to a slower pace of innovation compared to user-space applications.

eBPF: A Game Changer

eBPF fundamentally changes this dynamic. By enabling safe execution of user-written programs within the kernel, eBPF empowers developers to add functionalities on the fly. These programs are rigorously checked and compiled using a Just-In-Time (JIT) compiler for optimal performance. This has opened doors for a surge of eBPF-based projects addressing various needs, including high-performance networking, security enforcement, and comprehensive system monitoring.

Beyond Network Filtering: The Power of eBPF

While its name hints at a connection to network filtering, eBPF goes far beyond its predecessor, the Berkeley Packet Filter (BPF). Unlike BPF's focus on network traffic management, eBPF programs can access a vast array of resources within the kernel. This allows for functionalities beyond simple network filtering, including:

  • High-performance networking and load balancing for modern data centers and cloud environments.
  • Extracting fine-grained security data with minimal system overhead.
  • Application tracing for developers to gain insights into application behavior and troubleshoot performance issues.
  • Proactive security enforcement for applications and containers running on the system.

This is just the beginning. The potential applications of eBPF are constantly expanding as the developer community embraces its flexibility and power. With eBPF, the future of kernel extensions looks bright, promising a dynamic and adaptable environment for a wide range of use cases.

How eBPF works?

eBPF operates through a well-defined workflow that allows safe execution of custom code within the kernel space:

  • Program Creation: Developers craft the eBPF program using a designated language. This program outlines the specific actions it will perform within the kernel.
  • Loading and Verification: The program is then loaded into the kernel using user-space tools like bpftool. This tool acts as a bridge, facilitating interaction between the user and the kernel. Here, a critical step takes place: verification. The kernel meticulously examines the program to ensure it adheres to security measures. This includes checks for attempts to access unauthorized memory regions, safeguarding the system's stability.
  • Kernel Execution: If the program successfully passes verification, it's ready for action. The kernel takes the reins and executes the program along the code path defined within the program itself.
  • Result Retrieval: Finally, developers can retrieve the program's output from the designated location. This allows them to analyze the results and gain valuable insights gleaned from the kernel.

eBPF Architecture


The Linux kernel operates within a two-tier architecture:

  • User Space: This is where your standard applications run, managed by non-privileged users.
  • Kernel Space: This privileged space is reserved for core system processes and the kernel itself.

Traditionally, user-space applications like monitoring agents require the kernel's assistance to access low-level system data like information about system calls. This approach can be inefficient, consuming significant resources due to constant communication between user and kernel space.

The eBPF Advantage:

eBPF programs bridge this gap by executing directly within the kernel space. This grants them direct access to kernel-level resources, eliminating the need for resource-intensive communication between user and kernel. Imagine being able to inspect every call to the exec() system call (responsible for creating new processes) without relying on traditional applications. This direct access unlocks several key benefits for KubeSense.

Flexibility and Programmability of eBPF
  • Granular Visibility: eBPF programs are written in custom code, enabling them to address diverse use cases with a high degree of nuance. You can access all user-land and kernel-space memory and resources, providing a level of detail far exceeding traditional monitoring tools.
  • Tailored Observability: Unlike pre-defined tools, eBPF allows you to customize the data you view and how it's presented. This empowers KubeSense to deliver insights tailored to your specific needs.
Efficient Resource Utilization and Performance Monitoring

By running directly in the kernel, eBPF programs eliminate the overhead of user-space applications constantly requesting data from the kernel. This translates to significant efficiency gains for KubeSense, freeing up valuable resources for core container orchestration tasks.

Enhanced Security and Kernel-Level Visibility
  • Sandboxed Execution: eBPF programs operate within secure sandboxes, minimizing the risk of introducing security vulnerabilities or stability issues.
  • Verification Process: Every eBPF program undergoes rigorous verification before execution, ensuring its safety and compatibility with the kernel. This offers a clear advantage over methods like Linux kernel modules, which can potentially destabilize the system if buggy.
Dynamic Tracing and Observability Capabilities

The ability to insert custom code into the kernel on demand makes eBPF ideal for dynamic tracing and observability within containerized environments. KubeSense can leverage eBPF to track the behavior of a "living system" without requiring modifications to the kernel itself. This allows for real-time insights into your containerized applications.

Deploying eBPF Programs

This section dives into the practical steps of deploying eBPF programs to gain comprehensive visibility into your containerized environment. We'll explore the workflow from writing the code to its execution, showcasing the power of eBPF for container orchestration.

Writing and Compiling the eBPF Program
  • Language and Tools: eBPF code is typically written in a restricted version of C, offering a familiar syntax for developers. This code is then compiled into eBPF bytecode using Clang, the de facto standard compiler for eBPF programs.
  • Leveraging Helper Functions: When defining the program's functionality, you can utilize a rich set of kernel helper functions. These functions perform common operations like memory manipulation, retrieving process IDs (PIDs) and timestamps, and even facilitating communication with other applications through eBPF maps (discussed later). This extensive library reduces the need to write a significant amount of custom code from scratch. You can focus on the specific functionalities you require within your deployment.

Verification and Loading
  • Ensuring Program Safety: Before deploying your compiled eBPF program, a crucial step involves verification. The bpf() system call is used to pass the bytecode to the kernel verifier. This verification process meticulously examines the program to guarantee it operates within designated memory regions and doesn't introduce any potential risks to system stability.
  • JIT Compilation and Execution: If the verification process grants approval, the kernel's Just-In-Time (JIT) compiler transforms the program into machine code optimized for direct execution. Once loaded and verified, your program is ready to be attached to the specific code path you defined, whether it resides in kernel space, user space, or both.

Runtime and Program Interaction
  • Monitoring and Data Access: Once your eBPF program is executing, it actively monitors the designated code flow. Program input and output data can be accessed through two primary mechanisms:
    1. eBPF Maps: These act as specialized data structures within the kernel space, enabling communication and data exchange between your eBPF program and user-space applications like KubeSense.
    2. Predefined File Descriptors: These file descriptors provide another avenue for retrieving program results from the kernel.

eBPF Safety: Guaranteeing Power with Security

eBPF's immense power within the Linux kernel demands a robust security framework. Here's a breakdown of the multi-layered approach ensuring eBPF program safety:

Access Control: Keeping Unwanted Programs Out
  • Privileged Mode or Special Capability: By default, only privileged processes (running as root) or those with the CAP_BPF capability can load eBPF programs. This prevents untrusted programs from injecting potentially harmful code.
  • Limited Functionality for Unprivileged Users: When unprivileged eBPF is enabled (a specific configuration choice), unprivileged processes can load certain restricted eBPF programs. These programs have a reduced feature set and limited access to kernel resources.
The eBPF Verifier: A Gatekeeper for Safe Execution

Even authorized programs undergo rigorous scrutiny by the eBPF verifier. This ensures the program itself is well-behaved and doesn't introduce stability issues:

  • Guaranteed Completion: Programs must always reach an endpoint. They are not allowed to indefinitely block or loop forever. However, bounded loops with guaranteed exit conditions are permitted.
  • Memory Safety: Uninitialized variables and out-of-bounds memory access are strictly prohibited.
  • Program Size Constraints: eBPF programs cannot exceed defined size limitations.
  • Finite Complexity: The verifier analyzes all possible execution paths within the program. This analysis must complete within a designated complexity limit.

The verifier focuses on program safety, not its intended purpose. It ensures the program executes securely, not what actions it performs.

Hardening: Adding Layers of Protection

Upon successful verification, eBPF programs undergo a hardening process based on the loading process (privileged or unprivileged). This process adds further security safeguards:

  • Program Execution Protection: The kernel memory holding the eBPF program is read-only. Any attempt to modify the program, whether due to a bug or malicious intent, will trigger a kernel crash. This prevents execution of corrupted or manipulated code.
  • Spectre Mitigations: Speculative execution vulnerabilities in certain CPUs are addressed. These measures include masking memory access, verifying speculative execution paths, and utilizing Retpolines for specific call types.
  • Constant Blinding: Constants within the code are obscured to prevent "JIT spraying attacks." This tactic thwarts attackers from injecting malicious code disguised as constants, potentially exploiting a kernel bug to hijack program execution.
Abstracted Runtime Context: Controlled Data Access

eBPF programs cannot directly access arbitrary kernel memory. Data and structures outside the program's context can only be accessed through designated eBPF helpers. This guarantees consistent access methods and ensures that all data access adheres to the program's privileges:

  • Permission-Based Access: Programs can only read or modify data structures relevant to their function, and only if the verifier confirmed safe access during program loading.
  • Helper-Mediated Modifications: Modifying certain data structures requires using eBPF helpers, ensuring controlled and secure data manipulation.

In conclusion, eBPF's safety measures create a secure environment for leveraging its powerful capabilities within the Linux kernel. These multi-layered safeguards ensure program safety, restrict unauthorized access, and prevent malicious code execution.

Key Features and Use Cases

Here's a glimpse into the key features and benefits that make eBPF a game-changer for monitoring, observability, and overall system management:

  • Dynamic Programmability: Gone are the days of modifying kernel source code or deploying complex user-space applications. eBPF empowers you to write and execute custom programs directly within the kernel. This on-demand approach offers unparalleled flexibility for addressing specific needs.
  • Reduced Performance Overhead: Unlike traditional monitoring tools that constantly communicate with the kernel, eBPF programs operate within the kernel itself. This eliminates the need for context switching and data transfer, resulting in significantly lower CPU and memory consumption. Your system resources are freed up to focus on core workloads.
  • Standardized Observability Across Distributions: Say goodbye to compatibility concerns! eBPF is seamlessly integrated into the kernel source code of all modern Linux distributions. This ensures a consistent and standardized approach to monitoring and observability, regardless of your specific Linux environment.
These core features translate into a multitude of benefits a.k.a use cases for users:
  • Deeper Visibility: Craft custom eBPF programs to gain granular insights into kernel operations, network traffic, and application behavior.
  • Enhanced Security: eBPF programs operate in secure sandboxes and undergo rigorous verification before execution. This minimizes the risk of introducing vulnerabilities or security breaches.
  • Dynamic Tracing and Debugging: The ability to inject custom code on demand makes eBPF ideal for tracing and debugging complex issues within your system. You can pinpoint bottlenecks and troubleshoot problems in real-time.
  • Streamlined Network Management: eBPF empowers you to implement custom network filtering, traffic shaping, and load balancing techniques directly within the kernel, enhancing network performance and efficiency.

In essence, eBPF offers a powerful, efficient, and standardized way to gain deeper control and insights into your system, paving the way for improved performance, security, and overall system health.