Linux-eBPF-Verifier-Bypass-Research
I researched Linux eBPF verifier bypass techniques and translated static candidates into practical exploitation workflows.
Practical Exploitation of Linux eBPF Verifier Vulnerabilities (LTS 6.8)

Course: Security Verification and Testing - Second Year, First Semester
Author: Renato Mignone
Date: December 2025
Abstract
This project explores the security boundaries of eBPF (extended Berkeley Packet Filter), a revolutionary technology that allows user-defined programs to run safely inside the Linux kernel. While eBPF's verifier is designed to guarantee memory safety and prevent malicious code execution, certain logic bugs can potentially bypass these protections.
π README Hierarchy & Navigation
This project is documented across multiple README files organized hierarchically. Start here and follow the breadcrumbs to dive deeper:
βββ README.md (you are here)
β ββ Explains: eBPF fundamentals, verifier concepts, threat model, inherited work
β ββ Audience: Readers unfamiliar with eBPF or the project context
β ββ Next: See "My Objective: Practical Exploitation" section below, then proceed to src/README.md
β
βββ src/README.md
β ββ Explains: Exploitation workflow, VM setup, compilation pipeline, overall methodology
β ββ Audience: Readers ready to understand the practical approach and environment
β ββ Next: Proceed to src/exploits/README.md for detailed vulnerability analysis
β
βββ src/exploits/README.md
β ββ Explains: Multi-stage analysis methodology (bytecode β verifier β xlated β runtime)
β ββ Explains: 5 vulnerabilities with evidence chains and classification
β ββ Audience: Readers interested in the analysis approach and vulnerability summaries
β ββ Next: Drill into individual vulnerabilities (5_06a, 5_06b, 5_06d, 5_39, 5_46b)
β
βββ src/exploits/{vulnerability}/README.md (one per vulnerability)
ββ Explains: Deep technical analysis, bytecode dumps, verifier logs, exploitation mechanics
ββ Explains: Complete evidence chain from source code to runtime traces
ββ Audience: Readers performing detailed technical analysis or reproducing exploits
ββ Files: Specific PoC scripts, patch files, analysis logs
Quick Navigation:
- Just want overview? β Read this file (root README.md)
- Want to run the exploits? β Jump to src/README.md
- Want methodology & analysis? β See src/exploits/README.md
- Analyzing specific vulnerability? β See src/exploits/{vulnerability}/README.md folder
- What is eBPF?
- Threat Model
- Why Target LTS 6.8?
- eBPF Exploitation Primitives
- Inherited Work: What the Previous Team Did
- My Objective: Practical Exploitation
- Repository Structure
- Quick Start
- Progress Tracking
- References
What is eBPF?
Origins and Evolution
eBPF (extended Berkeley Packet Filter) is a revolutionary technology that originated from the classic BPF (Berkeley Packet Filter) created in 1992 for network packet filtering. While classic BPF was limited to simple packet inspection (used by tools like tcpdump), eBPF has evolved into a general-purpose in-kernel virtual machine capable of running sandboxed programs in the Linux kernel.
Timeline:
- 1992: BPF created (packet filtering only).
- 2014: eBPF introduced in Linux 3.18 (Extended instruction set, Maps, Helpers).
- 2016: XDP (eXpress Data Path) added for programmable network processing at the driver level.
- 2020+: eBPF becomes ubiquitous for Observability, Security, and Networking.
Architecture Overview
eBPF programs are written in a restricted C dialect, compiled to eBPF bytecode, verified by the kernel, and JIT-compiled to native machine code for execution.
Key Components:
| Component | Description |
|---|---|
| eBPF Bytecode | Platform-independent instruction set (11 registers, 64-bit) |
| Verifier | Static analyzer ensuring program safety before execution |
| JIT Compiler | Translates bytecode to native CPU instructions |
| Maps | Key-value stores for sharing data between eBPF programs and user space |
| Helpers | Kernel functions callable from eBPF (e.g., bpf_map_lookup_elem) |
| Hooks | Attachment points in kernel (kprobes, tracepoints, XDP, TC, LSM) |
The eBPF Verifier
The verifier is the security cornerstone of eBPF. It performs static analysis on every program before allowing it to run in the kernel. Its goal is to guarantee:
- Memory Safety β No out-of-bounds reads/writes
- Termination β Program will always complete (no infinite loops)
- Valid Operations β Only allowed helpers and operations
- Type Safety β Correct use of pointers and data types
Verifier Analysis Stages:
- CFG Construction: Build Control Flow Graph and identify execution paths.
- Instruction Walk: Simulate each instruction and track register states.
- Bounds Checking: Verify memory accesses and track pointer arithmetic.
- Loop Detection: Ensure bounded iteration.
- Helper Validation: Check argument types.
Verifier Limitations (The Attack Surface):
The verifier is complex (~20,000 lines of code in kernel/bpf/verifier.c) and must balance security, usability, and performance. This complexity creates potential for logic bugs where:
- The verifier's model of program behavior differs from actual execution.
- Edge cases in type tracking allow invalid operations.
- Pointer arithmetic confuses the verifier's bounds tracking.
These verifier bugs are the focus of this project.
How the Verifier Tracks State (The Logic)
To ensure safety without executing the code, the verifier simulates every instruction and maintains a state for each of the 11 registers (R0-R10). A vulnerability occurs when this internal state gets out of sync with the actual runtime machine state.
What the Verifier tracks per register:
- Type: Is it a SCALAR (number) or a POINTER (to memory/map)?
- Exploit Path: If we can trick the verifier into thinking a SCALAR is a POINTER, we can read arbitrary kernel memory.
- Range (
tnum): What is the min/max value this register holds?- Exploit Path: If the verifier thinks a value is
0-100but at runtime it is1000, bounds checks are bypassed (OOB R/W).
- Exploit Path: If the verifier thinks a value is
- Offset: Where does this pointer point relative to the base object?
The "Pruning" Problem: To save time, if the verifier sees a code path that looks similar to one it already checked, it skips it ("pruning"). Many logic bugs hide hereβwhere the verifier prunes a path it thought was safe, but actually wasn't.
Program Types and Use Cases
eBPF supports multiple program types, each attaching to different kernel hooks:
| Program Type | Hook Point | Use Case |
|---|---|---|
BPF_PROG_TYPE_XDP | Network driver (pre-stack) | DDoS mitigation, load balancing |
BPF_PROG_TYPE_SCHED_CLS | Traffic Control (TC) | Packet filtering, NAT |
BPF_PROG_TYPE_KPROBE | Kernel functions | Tracing, debugging |
BPF_PROG_TYPE_TRACEPOINT | Static kernel events | Performance monitoring |
BPF_PROG_TYPE_LSM | Linux Security Modules | Security policies |
BPF_PROG_TYPE_SOCKET_FILTER | Socket layer | Packet inspection |
XDP (eXpress Data Path) is particularly interesting for security research because it runs at the earliest point in the network stack, has direct memory access, and is performance-critical.
Security Implications
eBPF's ability to run custom code in kernel space makes it a high-value target for attackers.
- Intended Boundaries: Cannot access arbitrary memory, cannot call arbitrary functions.
- If Verifier Bypassed: Arbitrary kernel read (Info disclosure), Arbitrary kernel write (Privilege escalation).
Historical eBPF Vulnerabilities:
| CVE | Year | Description |
|---|---|---|
| CVE-2020-8835 | 2020 | Verifier bounds tracking error, arbitrary R/W |
| CVE-2021-3490 | 2021 | ALU32 bounds tracking, privilege escalation |
| CVE-2021-31440 | 2021 | Bounds propagation bug |
| CVE-2022-23222 | 2022 | Pointer arithmetic confusion |
| CVE-2023-2163 | 2023 | Verifier log buffer overflow |
This project focuses on identifying and exploiting similar verifier logic bugs in LTS 6.8.
Threat Model
Before diving into exploitation, it's essential to define the threat model β who is the attacker, what capabilities do they have, and what are they trying to achieve?
Attacker Profile
| Attribute | Description |
|---|---|
| Access Level | Unprivileged user access to a Linux system (LTS 6.8) |
| Capabilities | Can load eBPF programs (requires CAP_BPF or root, depending on kernel config) |
| Limitations | Cannot directly modify kernel code, modules, or bypass secure boot |
Attack Goals
| Goal | Impact | Severity |
|---|---|---|
| Arbitrary Kernel Read | Leak kernel addresses (defeat KASLR), credentials, cryptographic keys | High |
| Arbitrary Kernel Write | Modify cred structure β privilege escalation to root | Critical |
| Code Execution | Overwrite function pointers β execute arbitrary kernel code | Critical |
Attack Surface
The attack surface is specifically the eBPF verifier's static analysis logic:
- Discrepancies between verifier's model and actual runtime behavior
- Edge cases in type tracking (SCALAR vs. POINTER confusion)
- Bounds tracking errors in arithmetic operations
- Pruning logic that incorrectly assumes paths are equivalent
Out of Scope
- Kernel exploits not involving eBPF (use-after-free, race conditions)
- Hardware vulnerabilities (Spectre, Meltdown)
- Social engineering or physical access attacks
- Denial of Service (we focus on privilege escalation)
Why Target LTS 6.8?
The choice of Linux Kernel LTS 6.8 as the target is deliberate:
| Reason | Explanation |
|---|---|
| Long Term Support | LTS kernels are deployed in production for 2-6 years, meaning vulnerabilities have prolonged impact |
| Wide Deployment | Used in enterprise servers, cloud infrastructure (AWS, GCP, Azure), and embedded systems |
| Security Research Value | Vulnerabilities discovered here have real-world implications |
| Verifier Maturity | Contains the latest verifier improvements β if we can bypass it, older kernels are likely vulnerable too |
| Reproducibility | Stable, well-documented version ensures consistent testing environment |
| eBPF Feature Set | Supports all modern eBPF features (BTF, CO-RE, ringbuf) that might introduce new attack vectors |
Note: Findings on LTS 6.8 may also apply to other kernel versions with similar verifier code. Backporting analysis would be a valuable extension of this work.
eBPF Exploitation Primitives
Once the verifier is bypassed, attackers leverage specific primitives to achieve their goals. Understanding these is crucial for both offense and defense.
1. Out-of-Bounds Read (OOB-R)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Verifier believes: ptr can access [0, 100] β
β Reality: ptr can access [0, 1000] β
β β
β Result: Read kernel memory beyond allowed bounds β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Use Cases:
- Defeat KASLR: Leak kernel base address to calculate gadget locations
- Credential Theft: Read
task_struct->credto extract UIDs, capabilities - Key Extraction: Leak cryptographic keys from kernel memory
2. Out-of-Bounds Write (OOB-W)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Verifier believes: ptr can write [0, 64] β
β Reality: ptr can write [0, 512] β
β β
β Result: Overwrite adjacent kernel structures β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Use Cases:
- Privilege Escalation: Overwrite
cred->uidandcred->gidto 0 β instant root - Security Bypass: Modify
cred->cap_effectiveto grant all capabilities - Code Execution: Overwrite function pointers in kernel structures
3. Type Confusion
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Verifier believes: R1 = SCALAR (safe number) β
β Reality: R1 = POINTER (kernel address) β
β β
β Result: Arithmetic on "numbers" actually moves β
β pointers to arbitrary kernel locations β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Use Cases:
- Convert controlled integers into arbitrary kernel pointers
- Bypass pointer arithmetic restrictions
- Access memory regions the verifier thought were unreachable
Common Exploitation Flow
Inherited Work: What the Previous Team Did
The repository ebpf-exploitability-test/ contains work from a previous team (Francesco Rollo, Gianfranco Trad, Giorgio Fardo, Giovanni Nicosia) who performed a theoretical vulnerability assessment based on ISO-IEC TS 17961-2013 (C Secure Coding Standard).
The ISO-IEC TS 17961-2013 Standard
The previous team based their vulnerability assessment on ISO-IEC TS 17961-2013, titled "Information technology β Programming languages, their environments and system software interfaces β C Secure Coding Rules".
This technical specification defines 46 rules that identify common programming patterns in C that lead to undefined behavior, security vulnerabilities, or reliability issues. Each rule is numbered (5.1 through 5.46) and categorized by vulnerability type:
| Category | Rule Examples | Vulnerability Type |
|---|---|---|
| Memory Safety | 5.2, 5.20, 5.21, 5.35 | Buffer overflows, dangling pointers, uninitialized memory |
| Type Safety | 5.1, 5.10, 5.16 | Pointer casts, integer conversions, aliasing violations |
| Control Flow | 5.4, 5.17 | Missing switch defaults, assignment in conditionals |
| Data Handling | 5.24, 5.40, 5.46 | Format strings, tainted input propagation |
| Pointer Operations | 5.22, 5.36 | Invalid pointer arithmetic, pointer comparisons |
Why This Standard?
The team systematically applied each of these 46 rules to the XDP SynProxy code, asking:
"If we intentionally violate this rule, will the eBPF verifier catch it?"
This approach provides comprehensive coverage β rather than hunting for specific bugs, they tested the verifier against a standardized catalog of known vulnerability patterns.
Rules NOT Applicable to eBPF
Of the 46 rules, 22 are not applicable to eBPF due to fundamental architectural constraints:
| Constraint | Affected Rules | Reason |
|---|---|---|
| No Dynamic Memory | 5.2, 5.18, 5.21, 5.23, 5.34 | No malloc() or free() in eBPF |
| No Signal Handling | 5.3, 5.5, 5.7 | No signal handlers in kernel context |
| No File Operations | 5.12, 5.27, 5.41, 5.43 | No FILE structs or stdio |
| No Standard Library | 5.8, 5.19, 5.29, 5.32, 5.37, 5.42 | Limited libc access |
| Not Security-Relevant | 5.25, 5.38, 5.44 | Discarded as not useful for exploitation |
Applicable Rules: ~24 rules could be tested in the eBPF environment.
Key Finding: Of those 24 applicable rules, 21 violations passed the verifier β a concerning result that motivated this follow-up exploitation work.
What is XDP SynProxy?
The previous team focused exclusively on testing vulnerabilities within the XDP SynProxy implementation. To understand why this is a significant target, we need to understand the problem it solves.
The SYN Flood Attack
A SYN flood is a type of Denial-of-Service (DoS) attack that exploits the TCP three-way handshake:
The problem: Each SYN packet causes the server to allocate a Transmission Control Block (TCB) and wait for the ACK. Attackers send thousands of SYN packets with spoofed source IPs, exhausting the server's connection table while never completing the handshake.
The SYN Proxy Solution
A SYN Proxy acts as an intermediary that validates clients before forwarding connections to the real server:
SYN Cookies: Instead of storing state, the proxy encodes connection information (source IP, port, timestamp) into the sequence number of the SYN-ACK. When the client responds with ACK, the proxy can validate the cookie mathematically without having stored any state. Fake clients with spoofed IPs never receive the SYN-ACK, so they can't complete the handshake.
Why XDP for SYN Proxy?
Traditional SYN proxies operate in user space or higher in the kernel stack, which introduces latency. XDP (eXpress Data Path) solves this by running the SYN proxy logic at the earliest possible point β directly in the network driver:
XDP SynProxy advantages:
- Line-rate processing: Can handle millions of packets per second
- Zero-copy: Operates directly on packet memory in the driver
- Early drop: Malicious packets never enter the kernel stack
- CPU efficient: No context switches, minimal overhead
The Target: xdp_synproxy_kern.c
The file xdp_synproxy_kern.c is an eBPF/XDP implementation of a SYN proxy, taken from the Linux kernel selftests. It performs:
- Packet parsing: Ethernet β IP β TCP header dissection
- SYN detection: Identifies incoming TCP SYN packets
- Cookie generation: Creates cryptographic SYN cookies
- SYN-ACK crafting: Builds response packets with embedded cookies
- ACK validation: Verifies returning ACKs contain valid cookies
- Connection forwarding: Passes validated connections to the kernel
The previous team chose this target because:
- It's real production code from Linux kernel selftests
- It involves complex pointer arithmetic for packet parsing
- It uses multiple eBPF features (maps, helpers, tail calls)
- It's security-critical β bugs here could disable DDoS protection or leak information
- It's performance-critical β must process packets at wire speed
Important: XDP SynProxy is User Code, Not Kernel Code
A crucial distinction to understand: xdp_synproxy_kern.c is not part of the Linux kernel itself. It's an eBPF program β user-provided code that gets loaded into the kernel at runtime:
This is the power and danger of eBPF: anyone with appropriate privileges can load custom code that runs inside the kernel with full kernel privileges.
The Verifier as Security Gatekeeper
The eBPF verifier exists specifically to prevent malicious or buggy user code from compromising the kernel.
What the Testing Actually Proves
When we inject vulnerable code via patches and test against the verifier:
The "Translation Gap": C Vulnerabilities vs. Bytecode Reality
A critical insight from this research is that a vulnerability in the C source code does not guarantee an exploit in the kernel, even if the verifier allows it to load.
This discrepancy exists because the vulnerability must survive a complex translation chain:
- C Source: The vulnerability exists here (e.g., ISO-17961 violation).
- LLVM Compilation: The compiler translates C to eBPF Bytecode.
- The Filter Effect: The compiler may optimize away the vulnerable logic, dead-code eliminate the branch, or translate a complex memory violation into a benign register operation.
- JIT Compilation: The kernel translates Bytecode to Native Machine Code (x86/ARM).
Why "Verifier Pass" $\neq$ "Exploit": For a vulnerability to be exploitable, it must be preserved through this translation. Many "theoretical" C bugs disappear because eBPF's memory model (512-byte stack, 64-bit registers) forces the compiler to generate code that, by coincidence or constraint, is safe at runtime.
Example: A buffer overflow in C (memcpy(dst, src, user_len)) might compile to eBPF instructions that use bounded loop unrolling, where the compiler statically limits the copy to a safe maximum regardless of user_len.
Conclusion: We are not just exploiting C code; we are exploiting the Bytecode that the C code produces.
Implication for This Project: When developing PoCs, examining the C source alone is insufficient. I must verify vulnerabilities survive compilation by analyzing the eBPF bytecode with tools like llvm-objdump -d or bpftool prog dump xlated.
Why This Matters
The previous team found ~21 cases where the verifier incorrectly accepted vulnerable code:
| Outcome | Count | Meaning |
|---|---|---|
| Verifier blocked | ~14 | Security works β |
| Compiler blocked | ~8 | Never reached verifier |
| Verifier passed + Exploitable | ~9 | Security failure β PRIMARY TARGETS |
| Verifier passed + Limited | ~12 | Uncertain β SECONDARY TARGETS |
| Verifier passed + Safe | ~17 | Logic bugs but no security impact |
The 9 "Exploitable" and 12 "Limited" cases represent situations where:
- Intentionally vulnerable code was written
- The eBPF verifier failed to detect the vulnerability
- The code was loaded into the kernel
- The vulnerability is now potentially exploitable with kernel privileges
My task: Prove these theoretical vulnerabilities are actually dangerous by building working exploits.
Theoretical vs. Practical: The Gap
Understanding the distinction between the previous team's work and mine is crucial:
| Aspect | Previous Team (Theoretical) | My Work (Practical) |
|---|---|---|
| Core Question | "Does this code pass the verifier?" | "Can I actually exploit this to get root?" |
| Analysis Type | Source code analysis | Bytecode + runtime analysis |
| Output | Classification (YES/LIMITED/NO) | Working PoC exploits |
| Validation | Static assessment | Dynamic exploitation |
| Conclusion | "This COULD be dangerous" | "This IS dangerous, here's proof" |
| Deliverable | Vulnerability catalog | Functional exploit code |
The Gap: Knowing a vulnerability exists is different from proving it's exploitable. Many theoretical vulnerabilities fail in practice due to:
- Compiler optimizations neutralizing the bug
- Additional runtime checks not visible in static analysis
- Memory layout constraints preventing useful corruption
- Missing primitives to chain into full exploitation
My Contribution: Bridge this gap by transforming theoretical findings into practical proof.
Their Testing Environment
The previous team implemented a full client-server architecture for practical eBPF/XDP vulnerability testing. Their setup allows you to:
- Run a netcat server and client on separate hosts (or host and VM), with the XDP SynProxy eBPF program acting as a proxy in the middle.
- Use the
start_session.shscript to launch a tmux session that sets up:- The XDP SynProxy loader (attaches the eBPF program to the network interface)
- A netcat server (listening for TCP connections)
- Kernel trace output (for debugging and observing eBPF behavior)
- Simulate real network communication, with the XDP SynProxy program intercepting and processing packets between the client and server.
This architecture enables you to test how injected vulnerabilities in the eBPF program can be exploited via network packets, providing a realistic and interactive environment for security research.
How it works in practice:
- The netcat server is always running on the VM, listening for incoming TCP connections on port 80.
- The XDP SynProxy eBPF program is attached to the VM's network interface and intercepts all incoming packets before they reach the server.
- You use a netcat client (typically from your host machine) to connect to the VM's IP and port 80, sending crafted network packets.
- This setup allows you to observe how the XDP program processes, blocks, or is potentially exploited by these packets.
VM Infrastructure (virt/)
The vmctl.sh script provides complete VM lifecycle management:
# VM Management Commands
./vmctl.sh create ~/.ssh/id_rsa.pub # Create and provision new VM
./vmctl.sh connect # Connect to VM console
./vmctl.sh destroy # Tear down VM
VM Specifications:
| Parameter | Value |
|---|---|
| Base Image | Ubuntu 24.04 (Noble) Cloud Image |
| Memory | 4096 MB |
| vCPUs | 2 |
| Disk | 20 GB |
| Hypervisor | KVM/QEMU via libvirt |
Cloud-Init Provisioning: The VM is automatically configured on first boot using cloud-init with:
- Pre-installed development tools (
clang,llvm,bpftool,make) - SSH key injection for passwordless access
- Network configuration for XDP testing
- All required eBPF development dependencies
Key Design Decisions
-
Single VM topology: The team initially attempted a 3-veth (virtual Ethernet) topology to simulate client/proxy/server separation. However, virtual interfaces caused checksum offloading issues with SYN cookies β the kernel's checksum calculation differed from hardware expectations. They simplified to a single real interface where the XDP program, server, and client all run within or connect to the same VM.
-
tmux testing sessions: The
start_session.shscript creates a multi-pane tmux session with:- Pane 1: XDP SynProxy program output
- Pane 2: Netcat server listening for connections
- Pane 3: Packet monitoring / test commands
Understanding Patches and git apply
β οΈ Terminology Clarification: In standard software development, a "patch" typically means a fix for a bug or vulnerability. In this project, the meaning is inverted: our patches inject vulnerabilities into clean code, not remove them. We use the Git patch format purely as a delivery mechanism to systematically introduce specific, isolated vulnerabilities into the
xdp_synproxy_kern.ccodebase for testing purposes.
A patch (or diff) is a text file that describes the differences between two versions of a file. While patches are traditionally used to distribute bug fixes, in this research context they serve as vulnerability injection vectors β each patch transforms the clean, safe xdp_synproxy_kern.c into a version containing a specific ISO-17961 vulnerability.
Why Use Patches for Vulnerability Injection?
| Benefit | Description |
|---|---|
| Isolation | Each vulnerability exists in its own patch β no cross-contamination |
| Reproducibility | Anyone can recreate the exact vulnerable state |
| Reversibility | Easy to apply and revert (git apply -R) |
| Documentation | Patch metadata includes vulnerability description |
| Automation | xvtlas can iterate through patches programmatically |
Anatomy of a Patch File
From b5856aa7d76351adf1a201097c3a950c9e94502d Mon Sep 17 00:00:00 2001
From: author <email@example.com>
Date: Wed, 27 Aug 2025 13:10:03 +0200
Subject: [PATCH] feat(5.10a_exploit): intptrconv
---
XDPs/xdp_synproxy/xdp_synproxy_kern.c | 251 ++++++++++++++++++++++++++
1 file changed, 251 insertions(+)
diff --git a/XDPs/xdp_synproxy/xdp_synproxy_kern.c b/XDPs/xdp_synproxy/xdp_synproxy_kern.c
index 0d0d990..34a1474 100644
--- a/XDPs/xdp_synproxy/xdp_synproxy_kern.c β Original file
+++ b/XDPs/xdp_synproxy/xdp_synproxy_kern.c β Modified file
@@ -373,6 +431,9 @@ struct header_pointers { β Location marker
static __always_inline int tcp_dissect(void *data, void *data_end,
struct header_pointers *hdr)
{
+ __u32 data_base_truncated; β Lines starting with + are ADDED
+ void *calculated_ptr;
+
hdr->eth = data;
- old_line_here β Lines starting with - are REMOVED
if (hdr->eth + 1 > data_end)
Key elements:
- Header: Commit metadata (author, date, message)
- File path: Which file(s) are modified
- Hunks (
@@): Location markers showing line numbers +lines: Code being added-lines: Code being removed- Context lines: Unchanged lines for positioning
Git Apply Command
Git provides the git apply command to apply patches to the working directory:
# Apply a patch (modifies files but doesn't create a commit)
git apply patches/5_10a_exploit_intptrconv/0001-feat-5_10a_exploit.patch
# Check if patch would apply cleanly (dry-run)
git apply --check patches/5_10a_exploit_intptrconv/0001-feat-5_10a_exploit.patch
# Apply in reverse (remove the patch changes)
git apply -R patches/5_10a_exploit_intptrconv/0001-feat-5_10a_exploit.patch
# Alternative: git am creates a commit from the patch
git am patches/5_10a_exploit_intptrconv/0001-feat-5_10a_exploit.patch
Workflow in This Project
This approach allows:
- Clean separation: Each vulnerability is isolated in its own patch
- Easy testing: Apply one patch, test, revert, apply next
- Version control: Patches are trackable and reviewable
- Reproducibility: Anyone can recreate the exact vulnerable state
The xvtlas Automation Tool
xvtlas (XDP Verifier Testing Launch Automation Suite) is a custom Go tool created by the team to automate the repetitive workflow of testing vulnerability patches.
Why They Built It
Testing 60+ vulnerability patches manually would require:
- Apply patch to base file
- Compile with clang/LLVM
- Load program with bpftool
- Capture verifier output
- Record results
- Revert patch
- Repeat...
xvtlas automates this entire pipeline:
Usage Modes
1. Batch Testing (All Patches)
./xvtlas --export "./output/" \
--kernel "6.8" \
--patch-path ./patches/ \
--base-file ./xdp_synproxy_kern.c \
--save-logs --verbose
Processes all patches and generates a comprehensive CSV report.
2. Single Patch Interactive Mode
./xvtlas --run-single "./patches/5_10a_exploit/*.patch" \
--base-file "./xdp_synproxy_kern.c"
Applies one patch, compiles, and opens a tmux session for manual testing.
3. Cleanup
./xvtlas --destroy
Reverts git state and cleans up temporary files from previous sessions.
Output Structure
xvtlas_output/
βββ report.csv # Summary: patch, compiled?, verified?, loaded?
βββ 5_06a_argcomp/
β βββ make.log # Compiler output and warnings
β βββ verifier.log # eBPF verifier output
βββ 5_10a_exploit_intptrconv/
β βββ make.log
β βββ verifier.log
βββ ...
Their Methodology
They applied 46 C vulnerability rules to the target code to test the verifier's response.
What They Produced
| Artifact | Description |
|---|---|
| 60+ vulnerability patches | Each implements a specific ISO-IEC TS 17961-2013 rule violation |
Base target: xdp_synproxy_kern.c | Real XDP SYN proxy from Linux kernel selftests |
| xvtlas tool | Go automation suite for patch/compile/verify workflow |
| patches.csv | Summary table with exploitability classification |
| Detailed documentation | 1500+ lines explaining each vulnerability |
Their Results Summary
- 60 patches total
- 8 compilation failures (rejected before verifier).
- 14 blocked by eBPF verifier β (security works).
- 19 passed verifier but "not exploitable" (memory bounds still enforced).
- 9 passed verifier AND marked "exploitable" (These are my primary targets).
- 12 passed verifier with "limited" exploitability (Secondary targets).
Vulnerabilities Marked as "Exploitable"
| Patch | ISO Rule | Vulnerability Type | Their Assessment |
|---|---|---|---|
5_06a_argcomp | 5.6 | Function pointer mismatch | Register/stack corruption |
5_06b_argcomp | 5.6 | Wrong argument count | Stack memory overwrite |
5_10a_exploit_intptrconv | 5.10 | Pointer truncation bypass | Info disclosure |
5_14_nullref | 5.14 | Null pointer dereference | Invalid memory access |
5_17_swtchdflt | 5.17 | Missing switch default | Undefined firewall behavior |
5_20a_libptr | 5.20 | Buffer overflow (8 bytes) | Adjacent stack corruption |
5_20c_libptr | 5.20 | Type confusion overflow | 12-byte buffer overflow |
5_35_uninit_mem | 5.35 | Uninitialized memory read | Kernel stack data leak |
5_35a_unint_mem | 5.35 | Uninitialized memory read | Kernel stack data leak |
Vulnerabilities Marked as "Limited" Exploitability
These vulnerabilities passed the verifier but have uncertain or constrained exploitation potential:
| Patch | ISO Rule | Vulnerability Type | Their Assessment |
|---|---|---|---|
5_06d_argcomp | 5.6 | Wrong argument types | Value truncation (localized impact) |
5_14a_nullref | 5.14 | Null pointer dereference | Invalid access, no escape path |
5_16b_signconv | 5.16 | Signed conversion | Logic errors only |
5_33a_restrict | 5.33 | Restrict pointer violation | Logic/data corruption in stack |
5_33b_restrict | 5.33 | Restrict pointer violation | Local stack data corruption |
5_36a_ptrobj | 5.36 | Pointer comparison UB | Memory layout information leak |
5_36b_ptrobj | 5.36 | Context pointer comparison | Kernel layout info disclosure |
5_36c_ptrobj | 5.36 | Map pointer comparison | Heap organization leak |
5_39_taintnoproto | 5.39 | Tainted function pointer | Unpredictable logic behavior |
5_45_invfmtstr | 5.45 | Invalid format strings | Address leak via logging |
5_46b_taintsink | 5.46 | Tainted memory copy | Attacker-controlled packet alteration |
Vulnerabilities Marked as "Not Exploitable"
These vulnerabilities were either blocked by the compiler, blocked by the verifier, or passed but had no security impact:
Blocked by Compilation Errors (8 patches):
| Patch | Reason |
|---|---|
5_06c_argcomp | Conflicting types for function |
5_13_objdec | Conflicting types for variable |
5_13b_objdec | Conflicting types for variable |
5_22d_invptr | Array subscript out of bounds |
5_24a_usrfmt | Incompatible pointer types |
Blocked by eBPF Verifier (12 patches):
| Patch | Verifier Error |
|---|---|
5_4a_boolasgn | Infinite loop detected |
5_4b_boolasgn | Infinite loop detected |
5_06e_argcomp | R1 type=scalar expected=map_ptr |
5_10a_intptrconv | Pointer arithmetic with <<= prohibited |
5_10b_intptrconv | R1 invalid mem access 'scalar' |
5_14b_nullref | R7 invalid mem access 'map_value_or_null' |
5_16a_signconv | R8 offset outside packet |
5_20b_libptr | Invalid indirect access to stack |
5_22c_invptr | Invalid access to context parameter |
5_24b_usrfmt | Invalid access to context parameter |
5_35b_unint_mem | R1 invalid mem access 'scalar' |
5_40_taintformatio | Invalid indirect access to stack |
5_46a_taintsink | Unbounded min value not allowed |
5_46c_taintsink | Address R11 invalid (VLA attempt) |
Passed Verifier but Not Exploitable (19 patches):
| Patch | Reason |
|---|---|
5_01a/b/c_ptrcomp | Memory bounds still enforced by verifier |
5_9_padcomp | Logic non-determinism only, no memory exposure |
5_11_alignconv | Logical misinterpretation, not memory exploitable |
5_11a/c_alignconv | Logical misinterpretation, not memory exploitable |
5_15_addrescape | Dangling pointer but stack managed per-packet |
5_15a/b_addrescape | Dangling pointer but stack managed per-packet |
5_22_invptr | Verifier-enforced memory bounds |
5_22b/e/f_invptr | Logical misinterpretation only |
5_26a-e_diverr | Division by zero results in 0, no crash |
5_28_strmod | Read-only memory, program terminates |
5_30_intoflow | Two's complement arithmetic, no memory violation |
5_31a/b_nonnullcs | Controlled memory layout required |
Complete Vulnerability Summary
Total: 60 patches tested
β
ββββ YES (Exploitable): 9 patches βββββββββββββΊ PRIMARY TARGETS
β βββ Verifier bypassed, real security impact possible
β
ββββ LIMITED (Uncertain): 12 patches ββββββββββΊ SECONDARY TARGETS
β βββ Passed verifier, constrained exploitation potential
β
ββββ NO (Not Exploitable): 39 patches
βββ 8 blocked by compiler
βββ 14 blocked by verifier β (security works)
βββ 17 passed but no security impact
Potential investigation scope: 21 patches (9 YES + 12 LIMITED)
What They Did NOT Do
- β Create actual working exploits
- β Achieve arbitrary kernel read/write
- β Demonstrate privilege escalation
- β Validate impact on real kernel versions
They proved vulnerabilities can bypass the verifier, but stopped at theoretical classification.
Repository Structure
Project_EBPF/
βββ README.md # This file
βββ report/ # My exploitation reports (TODO)
βββ src/ # My PoC code (TODO)
β
βββ ebpf-exploitability-test/ # INHERITED FROM PREVIOUS TEAM
βββ codebase/
βββ README.md # Their documentation
βββ docs/
β βββ ISO-IEC-TS-17961-2013.pdf
β
βββ virt/ # VM management
β βββ vmctl.sh # Create/destroy/connect to test VM
β βββ meta-data.yaml
β
βββ XDPs/
β βββ xdp_synproxy/ # Main target
β β βββ xdp_synproxy_kern.c # Base vulnerable program
β β βββ Makefile
β β βββ patches/ # 60+ vulnerability patches
β β β βββ 5_10a_exploit_intptrconv/
β β β βββ 5_14_nullref/
β β β βββ 5_20a_libptr/
β β β βββ ...
β β βββ patches.csv # Summary of all patches
β β βββ apply_rules.sh
β β βββ start_session.sh
β β βββ kill_session.sh
β β
β βββ minimal/ # Minimal exploit examples
β β βββ 5_10a_exploit.c
β β
β βββ tools/ # BPF headers
β
βββ xvtlas/ # Automation tool (Go)
β βββ main.go
β βββ xvtlas # Pre-compiled binary
β βββ README.md
β
βββ xvtlas_output/ # Previous test results
βββ report.csv
βββ [per-patch logs]/
My Objective
My work builds directly on this existing client-server/XDP SynProxy architecture. Since the XDP program operates at the network interface, having two hosts (client and server) communicating through the proxy is essential for realistic exploitation.
My objective:
- Leverage the previous team's infrastructure to perform practical exploitation.
- Use network packets as the attack vector: generate and send them from a netcat client (on the host) to the netcat server (on the VM), with the XDP SynProxy eBPF program in the middle.
- Trigger and exploit vulnerabilities injected into the XDP interface via eBPF patches, by crafting specific network traffic.
- Demonstrate, with real network traffic, which vulnerabilities are exploitable in practice and document the exploitation process.
Goals
- Analyze the ~10 "exploitable" vulnerabilities in depth
- Develop working PoCs that demonstrate real kernel impact
- Document exploitation techniques and verifier bypass methods
- Validate severity on LTS 6.8 kernel
Quick Start (Using Inherited Infrastructure)
1. Set Up Test VM
cd ebpf-exploitability-test/codebase/virt/
./vmctl.sh create ~/.ssh/id_rsa.pub
./vmctl.sh connect
2. Test a Vulnerability Patch
# Inside VM
cd ~/ebpf-tests/XDPs/xdp_synproxy/
# Apply a patch
git apply patches/5_10a_exploit_intptrconv/0001-feat-5_10a_exploit.patch
# Compile
make
# Test
./start_session.sh
3. Use xvtlas Automation
cd xvtlas/
./xvtlas --run-single "./patches/5_10a_exploit_intptrconv/*.patch" \
--base-file "./xdp_synproxy_kern.c"
Practical Exploitation Workflow: Step-by-Step
Prerequisite: Automated Extraction of vmlinux.h for eBPF Compilation
Before compiling the XDP SynProxy eBPF program, the vmlinux.h header is automatically generated from your running kernel's BTF data by the session script. This file provides all kernel type definitions needed for CO-RE (Compile Once, Run Everywhere) eBPF development.
Automated vmlinux.h extraction:
The following command is run automatically by start_session.sh before compilation:
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c > /mnt/shared/XDPs/xdp_synproxy/vmlinux.h
You only need to run make in /mnt/shared/XDPs/xdp_synproxy after starting the VM and session script. If your shared folder path is different, adjust the output path accordingly.
Why is this needed?
- The eBPF kernel program uses CO-RE features and requires accurate kernel type definitions.
- If
vmlinux.his missing, compilation will fail with an error about the missing file.
This section explains the full process for exploiting eBPF verifier vulnerabilities using the inherited infrastructure, including how the Makefile, scripts, and tmux sessions fit together. It also clarifies the difference between the previous team's theoretical work and the practical exploitation phase.
1. Compilation and Loading: The Role of the Makefile
The Makefile in ebpf-exploitability-test/codebase/XDPs/xdp_synproxy/ is responsible for compiling:
- The eBPF kernel program (
xdp_synproxy_kern.c) into bytecode (xdp_synproxy_kern.bpf.o) - The user-space loader (
xdp_synproxy.c) into an executable (xdp_synproxy)
Workflow:
- Run
makein the target folder to build both binaries. - The user-space loader is run with
sudoto load the eBPF program into the kernel. The eBPF verifier automatically checks the code at load time. - If the code passes, it is loaded and runs in the kernel; if not, it is rejected.
2. Applying Vulnerability Patches
The previous team provided 60+ patches, each injecting a specific vulnerability (based on ISO-IEC TS 17961-2013) into the base code. These patches are applied using git apply:
git apply patches/<patch-folder>/<patch-file>.patch
make clean && make
This allows you to test if the eBPF verifier blocks or accepts the vulnerable code.
3. Setting Up the Test Environment: tmux Sessions and Scripts
The start_session.sh script in the same folder sets up a multi-pane tmux session for interactive testing:
- Pane 1: Runs the XDP SynProxy loader (
sudo ./xdp_synproxy ...) to attach the eBPF program to the network interface. - Pane 2: Starts a netcat server (
sudo nc -lvnp 80) to listen for TCP connections. - Pane 3: Shows kernel debug output (
sudo cat /sys/kernel/debug/tracing/trace_pipe).
This environment allows you to:
- Observe how the eBPF program processes packets
- See the effects of injected vulnerabilities
- Test exploitation by sending crafted packets from a client (e.g., using netcat from the host)
4. Exploitation: Client-Server Interaction
After the tmux session is running:
- The netcat server listens for incoming TCP connections.
- The client (your host machine or another VM) connects using netcat:
nc <VM_IP> 80 -v - This simulates an attacker sending packets to exploit the loaded eBPF program.
- The kernel trace and server output help you observe if the vulnerability is exploitable.
5. Theoretical vs. Practical: What Changes
Previous Team (Theoretical):
- Catalogued vulnerabilities and tested if the eBPF verifier would block them.
- Did not attempt real exploitation or privilege escalation.
Your Work (Practical):
- Apply patches, compile, and load the code.
- Use the tmux session to simulate real attacks and observe kernel impact.
- Document which vulnerabilities are truly exploitable in practice.
6. Automation Tools
The xvtlas tool (Go-based) can automate patch application, compilation, loading, and result collection for batch testing.
Summary of Practical Exploitation Steps
- Start the VM using
vmctl.shand connect. - Compile the base or patched code with
make. - Load the eBPF program using the user-space loader (verifier checks it automatically).
- Start the tmux session with
start_session.sh. - Simulate client attacks using netcat from the host.
- Observe results in tmux panes and kernel trace.
- Document findings: Did the verifier block the vulnerability? Was it exploitable?
This workflow bridges the gap between theoretical vulnerability assessment and practical exploitation, providing a reproducible, automated environment for eBPF security research.
Progress Tracking
- Environment setup (VM, kernel 6.8)
- Study inherited codebase
- Analyze priority vulnerabilities
- Develop PoC #1: (TBD)
- Develop PoC #2: (TBD)
- Write exploitation report
- Final documentation
References
- ISO-IEC TS 17961-2013 - C Secure Coding Standard
- eBPF Documentation
- Linux Kernel BPF Verifier
- Previous team's detailed documentation:
ebpf-exploitability-test/codebase/XDPs/xdp_synproxy/README.md
Priority Vulnerabilities for Practical Exploitation
The following vulnerabilities are the primary focus for practical exploitation in this project:
- 5.6a argcomp β Function pointer type incompatibility
- 5.6b argcomp β Wrong number of arguments
- 5.6d argcomp β Wrong argument types
- 5.39 taintnoproto β Using tainted values as function pointers without prototypes
- 5.46b taintsink β Memory copy with tainted length
π Next Steps
Now that you understand the context and objectives, proceed to the practical exploitation documentation:
β Continue to src/README.md to learn about the exploitation workflow, environment setup, and overall methodology.