Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
rbpf — Rust virtual machine and JIT compiler for eBPF programs | Kitploit
Tools/GitHubGitHub/qmonnet/rbpf
Embedded Systems SecurityPacket Sniffing & AnalysisDynamic Analysis (Sandboxing)Reverse EngineeringNetwork SecurityUtilities & FrameworksBinary Analysis
GitHubqmonnet/rbpf

rbpf

Rust virtual machine and JIT compiler for eBPF programs

View Repository
1.1k3774 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

rbpf

Rust (user-space) virtual machine for eBPF

Build Status Build status Coverage Status Crates.io

  • Description
  • Link to the crate
  • API
  • Example uses
  • Building eBPF programs
  • Build Features
  • Feedback welcome!
  • Questions / Answers
  • Caveats
  • To do list
  • License
  • Inspired by
  • Other resources

Description

This crate contains a virtual machine for eBPF program execution. BPF, as in Berkeley Packet Filter, is an assembly-like language initially developed for BSD systems, in order to filter packets in the kernel with tools such as tcpdump so as to avoid useless copies to user-space. It was ported to Linux, where it evolved into eBPF (extended BPF), a faster version with more features. While BPF programs are originally intended to run in the kernel, the virtual machine of this crate enables running it in user-space applications; it contains an interpreter, an x86_64 JIT-compiler for eBPF programs, as well as a disassembler.

It is based on Rich Lane's uBPF software, which does nearly the same, but is written in C.

The crate is supposed to compile and run on Linux, MacOS X, and Windows, although the JIT-compiler does not work with Windows at this time.

Link to the crate

This crate is available from crates.io, so it should work out of the box by adding it as a dependency in your Cargo.toml file:

[dependencies]
rbpf = "0.4.1"

You can also use the development version from this GitHub repository. This should be as simple as putting this inside your Cargo.toml:

[dependencies]
rbpf = { git = "https://github.com/qmonnet/rbpf" }

Of course, if you prefer, you can clone it locally, possibly hack the crate, and then indicate the path of your local version in Cargo.toml:

[dependencies]
rbpf = { path = "path/to/rbpf" }

Then indicate in your source code that you want to use the crate:

extern crate rbpf;

API

The API is pretty well documented inside the source code. You should also be able to access an online version of the documentation from here, automatically generated from the crates.io version (may not be up-to-date with the main branch). Examples and unit tests should also prove helpful. Here is a summary of how to use the crate.

Here are the steps to follow to run an eBPF program with rbpf:

  1. Create a virtual machine. There are several kinds of machines, we will come back on this later. When creating the VM, pass the eBPF program as an argument to the constructor.
  2. If you want to use some helper functions, register them into the virtual machine.
  3. If you want a JIT-compiled program, compile it.
  4. Execute your program: either run the interpreter or call the JIT-compiled function.

eBPF has been initially designed to filter packets (now it has some other hooks in the Linux kernel, such as kprobes, but this is not covered by rbpf). As a consequence, most of the load and store instructions of the program are performed on a memory area representing the packet data. However, in the Linux kernel, the eBPF program does not immediately access this data area: initially, it has access to a C struct sk_buff instead, which is a buffer containing metadata about the packet—including memory addresses of the beginning and of the end of the packet data area. So the program first loads those pointers from the sk_buff, and then can access the packet data.

This behavior can be replicated with rbpf, but it is not mandatory. For this reason, we have several structs representing different kinds of virtual machines:

  • struct EbpfVmMbuffer mimics the kernel. When the program is run, the address provided to its first eBPF register will be the address of a metadata buffer provided by the user, and that is expected to contain pointers to the start and the end of the packet data memory area.

  • struct EbpfVmFixedMbuff has one purpose: enabling the execution of programs created to be compatible with the kernel, while saving the effort to manually handle the metadata buffer for the user. In fact, this struct has a static internal buffer that is passed to the program. The user has to indicate the offset values at which the eBPF program expects to find the start and the end of packet data in the buffer. On calling the function that runs the program (JITted or not), the struct automatically updates the addresses in this static buffer, at the appointed offsets, for the start and the end of the packet data the program is called upon.

  • struct EbpfVmRaw is for programs that want to run directly on packet data. No metadata buffer is involved, the eBPF program directly receives the address of the packet data in its first register. This is the behavior of uBPF.

  • struct EbpfVmNoData does not take any data. The eBPF program takes no argument whatsoever and its return value is deterministic. Not so sure there is a valid use case for that, but if nothing else, this is very useful for unit tests.

All these structs implement the same public functions:

// called with EbpfVmMbuff:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmMbuff<'a>, Error>

// called with EbpfVmFixedMbuff:: prefix
pub fn new(prog: &'a [u8],
           data_offset: usize,
           data_end_offset: usize) -> Result<EbpfVmFixedMbuff<'a>, Error>

// called with EbpfVmRaw:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmRaw<'a>, Error>

// called with EbpfVmNoData:: prefix
pub fn new(prog: &'a [u8]) -> Result<EbpfVmNoData<'a>, Error>

This is used to create a new instance of a VM. The return type is dependent of the struct from which the function is called. For instance, rbpf::EbpfVmRaw::new(Some(my_program)) would return an instance of struct rbpf::EbpfVmRaw (wrapped in a Result). When a program is loaded, it is checked with a very simple verifier (nothing close to the one for Linux kernel). Users are also able to replace it with a custom verifier.

For struct EbpfVmFixedMbuff, two additional arguments must be passed to the constructor: data_offset and data_end_offset. They are the offset (byte number) at which the pointers to the beginning and to the end, respectively, of the memory area of packet data are to be stored in the internal metadata buffer each time the program is executed. Other structs do not use this mechanism and do not need those offsets.

// for struct EbpfVmMbuff, struct EbpfVmRaw and struct EbpfVmRawData
pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error>

// for struct EbpfVmFixedMbuff
pub fn set_program(&mut self, prog: &'a [u8],
                data_offset: usize,
                data_end_offset: usize) -> Result<(), Error>
Download Tool