Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/qmonnet/rbpf"
readme = "README.md"
keywords = ["BPF", "eBPF", "interpreter", "JIT", "filtering"]
license = "Apache-2.0/MIT"
edition = "2021"
edition = "2024"

# Packaging directives
include = [
Expand All @@ -27,24 +27,24 @@ include = [

# Default features (std) are disabled so that the dependencies don't pull in the
# standard library when the crate is compiled for no_std
byteorder = { version = "1.2", default-features = false }
log = { version = "0.4.21", default-features = false }
byteorder = { version = "1.5", default-features = false }
log = { version = "0.4", default-features = false }
combine = { version = "4.6", default-features = false }

# Optional Dependencies when using the standard library
libc = { version = "0.2", optional = true }

# Optional Dependencies for the CraneLift JIT
cranelift-codegen = { version = "0.99", optional = true }
cranelift-frontend = { version = "0.99", optional = true }
cranelift-jit = { version = "0.99", optional = true }
cranelift-native = { version = "0.99", optional = true }
cranelift-module = { version = "0.99", optional = true }
hashbrown = { version = "0.15", default-features = false, features = ["default-hasher"] }
cranelift-codegen = { version = "0.127", optional = true }
cranelift-frontend = { version = "0.127", optional = true }
cranelift-jit = { version = "0.127", optional = true }
cranelift-native = { version = "0.127", optional = true }
cranelift-module = { version = "0.127", optional = true }
hashbrown = { version = "0.16", default-features = false, features = ["default-hasher"] }

[dev-dependencies]
libc = { version = "0.2" }
elf = "0.0.10"
elf = "0.8.0"
json = "0.12"
hex = "0.4.3"

Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ for each run of the program.

```rust
extern crate elf;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use std::path::PathBuf;

extern crate rbpf;
Expand All @@ -414,19 +416,21 @@ fn main() {
let filename = "examples/load_elf__block_a_port.o";

let path = PathBuf::from(filename);
let file = match elf::File::open_path(&path) {
Ok(f) => f,
Err(e) => panic!("Error: {:?}", e),
};
let file_data = std::fs::read(path).expect("Could not read file");
let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");

// Here we assume the eBPF program is in the ELF section called
// ".classifier".
let text_scn = match file.get_section(".classifier") {
Some(s) => s,
None => panic!("Failed to look up .classifier section"),
let classifier_section_header = match file.section_header_by_name(".classifier") {
Ok(Some(header)) => header,
Ok(None) => panic!("No .classifier section found"),
Err(e) => panic!("Error while searching for .classifier section: {}", e),
};

let prog = &text_scn.data;
let prog = file
.section_data(&classifier_section_header)
.expect("Failed to get .classifier section data").0;

// This is our data: a real packet, starting with Ethernet header
let packet = &mut [
Expand Down
25 changes: 22 additions & 3 deletions examples/allowed_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Copyright 2024 Akenes SA <[email protected]>

extern crate elf;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use std::path::PathBuf;
use std::{ptr::addr_of};

extern crate rbpf;
Expand Down Expand Up @@ -31,11 +34,27 @@ fn bpf_lookup_elem(_map: u64, key_addr: u64, _flags: u64, _u4: u64, _u5: u64) ->
0
}

fn get_prog_data(filename: &str) -> Vec<u8> {
let path = PathBuf::from(filename);
let file_data = std::fs::read(path).expect("Could not read file");
let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");

let classifier_section_header = match file.section_header_by_name("classifier") {
Ok(Some(header)) => header,
Ok(None) => panic!("No .classifier section found"),
Err(e) => panic!("Error while searching for classifier section: {}", e),
};

file
.section_data(&classifier_section_header)
.expect("Failed to get classifier section data").0.to_vec()
}

fn main() {
let file = elf::File::open_path(OBJ_FILE_PATH).unwrap();
let func = file.get_section("classifier").unwrap();
let prog = get_prog_data(OBJ_FILE_PATH);

let mut vm = rbpf::EbpfVmNoData::new(Some(&func.data)).unwrap();
let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
vm.register_helper(BPF_MAP_LOOKUP_ELEM_IDX, bpf_lookup_elem)
.unwrap();

Expand Down
20 changes: 12 additions & 8 deletions examples/load_elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Copyright 2016 6WIND S.A. <[email protected]>

extern crate elf;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use std::path::PathBuf;

extern crate rbpf;
Expand Down Expand Up @@ -49,17 +51,19 @@ fn main() {
let filename = "examples/load_elf__block_a_port.o";

let path = PathBuf::from(filename);
let file = match elf::File::open_path(path) {
Ok(f) => f,
Err(e) => panic!("Error: {e:?}"),
};
let file_data = std::fs::read(path).expect("Could not read file");
let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");

let text_scn = match file.get_section(".classifier") {
Some(s) => s,
None => panic!("Failed to look up .classifier section"),
let classifier_section_header = match file.section_header_by_name(".classifier") {
Ok(Some(header)) => header,
Ok(None) => panic!("No .classifier section found"),
Err(e) => panic!("Error while searching for .classifier section: {}", e),
};

let prog = &text_scn.data;
let prog = file
.section_data(&classifier_section_header)
.expect("Failed to get .classifier section data").0;

#[rustfmt::skip]
let packet1 = &mut [
Expand Down
20 changes: 12 additions & 8 deletions examples/to_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
extern crate json;

extern crate elf;
use elf::endian::AnyEndian;
use elf::ElfBytes;
use std::path::PathBuf;

extern crate rbpf;
Expand Down Expand Up @@ -58,17 +60,19 @@ fn main() {
let filename = "examples/load_elf__block_a_port.o";

let path = PathBuf::from(filename);
let file = match elf::File::open_path(path) {
Ok(f) => f,
Err(e) => panic!("Error: {e:?}"),
};
let file_data = std::fs::read(path).expect("Could not read file");
let slice = file_data.as_slice();
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");

let text_scn = match file.get_section(".classifier") {
Some(s) => s,
None => panic!("Failed to look up .classifier section"),
let classifier_section_header = match file.section_header_by_name(".classifier") {
Ok(Some(header)) => header,
Ok(None) => panic!("No .classifier section found"),
Err(e) => panic!("Error while searching for .classifier section: {}", e),
};

let prog = &text_scn.data;
let prog = file
.section_data(&classifier_section_header)
.expect("Failed to get .classifier section data").0;

println!("{}", to_json(prog));
}
5 changes: 2 additions & 3 deletions src/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,10 @@ fn assemble_internal(parsed: &[Instruction]) -> Result<Vec<Insn>, String> {
Err(msg) => return Err(format!("Failed to encode {name}: {msg}")),
}
// Special case for lddw.
if let LoadImm = inst_type {
if let Integer(imm) = instruction.operands[1] {
if let LoadImm = inst_type
&& let Integer(imm) = instruction.operands[1] {
result.push(insn(0, 0, 0, 0, imm >> 32).unwrap());
}
}
}
None => return Err(format!("Invalid instruction {name:?}")),
}
Expand Down
27 changes: 14 additions & 13 deletions src/cranelift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,17 @@ impl CraneliftCompiler {
entry: Block,
) -> Result<(), Error> {
// Register the VM registers as variables
for var in self.registers.iter() {
bcx.declare_var(*var, I64);
for var in self.registers.iter_mut() {
*var = bcx.declare_var(I64);
}

// Register the bounds check variables
bcx.declare_var(self.mem_start, I64);
bcx.declare_var(self.mem_end, I64);
bcx.declare_var(self.mbuf_start, I64);
bcx.declare_var(self.mbuf_end, I64);
bcx.declare_var(self.stack_start, I64);
bcx.declare_var(self.stack_end, I64);
self.mem_start = bcx.declare_var(I64);
self.mem_end = bcx.declare_var(I64);
self.mbuf_start = bcx.declare_var(I64);
self.mbuf_end = bcx.declare_var(I64);
self.stack_start = bcx.declare_var(I64);
self.stack_end = bcx.declare_var(I64);

// Register the helpers
for (k, _) in self.helpers.iter() {
Expand All @@ -197,10 +197,11 @@ impl CraneliftCompiler {
}

// Register the stack
let ss = bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
size: STACK_SIZE as u32,
});
let ss = bcx.create_sized_stack_slot(StackSlotData::new(
StackSlotKind::ExplicitSlot,
STACK_SIZE as u32,
0,
));
let addr_ty = self.isa.pointer_type();
let stack_addr = bcx.ins().stack_addr(addr_ty, ss, STACK_SIZE as i32);
bcx.def_var(self.registers[10], stack_addr);
Expand Down Expand Up @@ -1070,7 +1071,7 @@ impl CraneliftCompiler {

// TODO: We can potentially throw a custom trap code here to indicate
// which check failed.
bcx.ins().trapz(valid, TrapCode::HeapOutOfBounds);
bcx.ins().trapz(valid, TrapCode::HEAP_OUT_OF_BOUNDS);
}

/// Analyze the program and build the CFG
Expand Down
5 changes: 2 additions & 3 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,10 @@ pub fn execute_program(
let mut insn_ptr: usize = 0;
while insn_ptr * ebpf::INSN_SIZE < prog.len() {
let insn = ebpf::get_insn(prog, insn_ptr);
if stack_frame_idx < MAX_CALL_DEPTH {
if let Some(usage) = stack_usage.stack_usage_for_local_func(insn_ptr) {
if stack_frame_idx < MAX_CALL_DEPTH
&& let Some(usage) = stack_usage.stack_usage_for_local_func(insn_ptr) {
stacks[stack_frame_idx].set_stack_usage(usage);
}
}
insn_ptr += 1;
let _dst = insn.dst as usize;
let _src = insn.src as usize;
Expand Down
52 changes: 26 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,18 +600,18 @@ impl<'a> EbpfVmMbuff<'a> {
// The last two arguments are not used in this function. They would be used if there was a
// need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
// should be stored; this is what happens with struct EbpfVmFixedMbuff.
match &self.jit {
Some(jit) => Ok(jit.get_prog()(
mbuff.as_ptr() as *mut u8,
mbuff.len(),
mem_ptr,
mem.len(),
0,
0,
)),
None => Err(Error::other(
"Error: program has not been JIT-compiled",
)),
unsafe {
match &self.jit {
Some(jit) => Ok(jit.get_prog()(
mbuff.as_ptr() as *mut u8,
mbuff.len(),
mem_ptr,
mem.len(),
0,
0,
)),
None => Err(Error::other("Error: program has not been JIT-compiled")),
}
}
}

Expand Down Expand Up @@ -1219,18 +1219,18 @@ impl<'a> EbpfVmFixedMbuff<'a> {
_ => mem.as_ptr() as *mut u8,
};

match &self.parent.jit {
Some(jit) => Ok(jit.get_prog()(
self.mbuff.buffer.as_ptr() as *mut u8,
self.mbuff.buffer.len(),
mem_ptr,
mem.len(),
self.mbuff.data_offset,
self.mbuff.data_end_offset,
)),
None => Err(Error::other(
"Error: program has not been JIT-compiled",
)),
unsafe {
match &self.parent.jit {
Some(jit) => Ok(jit.get_prog()(
self.mbuff.buffer.as_ptr() as *mut u8,
self.mbuff.buffer.len(),
mem_ptr,
mem.len(),
self.mbuff.data_offset,
self.mbuff.data_end_offset,
)),
None => Err(Error::other("Error: program has not been JIT-compiled")),
}
}
}

Expand Down Expand Up @@ -1723,7 +1723,7 @@ impl<'a> EbpfVmRaw<'a> {
#[cfg(not(windows))]
pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
let mut mbuff = vec![];
self.parent.execute_program_jit(mem, &mut mbuff)
unsafe { self.parent.execute_program_jit(mem, &mut mbuff) }
}

/// Compile the loaded program using the Cranelift JIT.
Expand Down Expand Up @@ -2133,7 +2133,7 @@ impl<'a> EbpfVmNoData<'a> {
/// ```
#[cfg(not(windows))]
pub unsafe fn execute_program_jit(&self) -> Result<u64, Error> {
self.parent.execute_program_jit(&mut [])
unsafe { self.parent.execute_program_jit(&mut []) }
}

/// Compile the loaded program using the Cranelift JIT.
Expand Down
23 changes: 15 additions & 8 deletions tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,27 @@ fn test_vm_block_port() {
// Cargo.toml). See comments above.
//
// ---
// extern crate elf;
// use elf::endian::AnyEndian;
// use elf::ElfBytes;
// use std::path::PathBuf;
//
// let filename = "my_ebpf_object_file.o";
//
// let path = PathBuf::from(filename);
// let file = match elf::File::open_path(&path) {
// Ok(f) => f,
// Err(e) => panic!("Error: {:?}", e),
// };
// let file_data = std::fs::read(path).expect("Could not read file");
// let slice = file_data.as_slice();
// let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");
//
// let text_scn = match file.get_section(".classifier") {
// Some(s) => s,
// None => panic!("Failed to look up .classifier section"),
// let classifier_section_header = match file.section_header_by_name(".classifier") {
// Ok(Some(header)) => header,
// Ok(None) => panic!("No .classifier section found"),
// Err(e) => panic!("Error while searching for .classifier section: {}", e),
// };
//
// let prog = &text_scn.data;
// let prog = file
// .section_data(&classifier_section_header)
// .expect("Failed to get .classifier section data").0;
// ---

#[rustfmt::skip]
Expand Down
Loading