Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ 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 }
log = { version = "0.4.21", default-features = false }
combine = { version = "4.6", default-features = false }

# Optional Dependencies when using the standard library
Expand All @@ -41,9 +41,13 @@ 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 = [
"alloc",
"default-hasher",
] }

[dev-dependencies]

libc = { version = "0.2" }
elf = "0.0.10"
json = "0.11"
hex = "0.4.3"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ useful for programs that should be compatible with the Linux kernel and
therefore must use specific helper numbers.

```rust,ignore
pub fn register_allowed_memory(&mut self,, addr: &[u64]) -> ()
pub fn register_allowed_memory(&mut self, addrs_range: Range<u64>) -> ()
```

This function adds a list of memory addresses that the eBPF program is allowed
Expand Down
5 changes: 2 additions & 3 deletions examples/allowed_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Akenes SA <wouter.dullaert@exoscale.ch>

extern crate elf;
use std::{iter::FromIterator, ptr::addr_of};
use std::{ptr::addr_of};

extern crate rbpf;

Expand Down Expand Up @@ -40,8 +40,7 @@ fn main() {
.unwrap();

let start = addr_of!(MAP_VALUE) as u64;
let addrs = Vec::from_iter(start..start + size_of::<Value>() as u64);
vm.register_allowed_memory(&addrs);
vm.register_allowed_memory(start..start + size_of::<Value>() as u64);

let res = vm.execute_program().unwrap();
assert_eq!(res, 1);
Expand Down
7 changes: 4 additions & 3 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::ebpf;
use crate::ebpf::MAX_CALL_DEPTH;
use crate::lib::*;
use crate::stack::{StackFrame, StackUsage};
use core::ops::Range;

#[allow(clippy::too_many_arguments)]
fn check_mem(
Expand All @@ -19,7 +20,7 @@ fn check_mem(
mbuff: &[u8],
mem: &[u8],
stack: &[u8],
allowed_memory: &HashSet<u64>,
allowed_memory: &HashSet<Range<u64>>,
) -> Result<(), Error> {
if let Some(addr_end) = addr.checked_add(len as u64) {
if mbuff.as_ptr() as u64 <= addr && addr_end <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
Expand All @@ -31,7 +32,7 @@ fn check_mem(
if stack.as_ptr() as u64 <= addr && addr_end <= stack.as_ptr() as u64 + stack.len() as u64 {
return Ok(());
}
if allowed_memory.contains(&addr) {
if allowed_memory.iter().any(|range| range.contains(&addr)) {
return Ok(());
}
}
Expand All @@ -51,7 +52,7 @@ pub fn execute_program(
mem: &[u8],
mbuff: &[u8],
helpers: &HashMap<u32, ebpf::Helper>,
allowed_memory: &HashSet<u64>,
allowed_memory: &HashSet<Range<u64>>,
) -> Result<u64, Error> {
const U32MAX: u64 = u32::MAX as u64;
const SHIFT_MASK_64: u64 = 0x3f;
Expand Down
69 changes: 50 additions & 19 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,12 @@

#![allow(clippy::single_match)]

use std::alloc;
use std::collections::HashMap;
use std::fmt::Error as FormatterError;
use std::fmt::Formatter;
use std::io::{Error, ErrorKind};
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;

use crate::ebpf;

extern crate libc;
use crate::{ebpf, format, vec, Error, ErrorKind, HashMap, Vec};
use core::fmt::Error as FormatterError;
use core::fmt::Formatter;
use core::mem;
use core::ops::{Index, IndexMut};
use core::ptr;

type MachineCode = unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64;

Expand Down Expand Up @@ -1001,11 +995,11 @@ impl JitCompiler {

// Assumes jump offset is at end of instruction
unsafe {
let offset_loc = jump.offset_loc as i32 + std::mem::size_of::<i32>() as i32;
let offset_loc = jump.offset_loc as i32 + core::mem::size_of::<i32>() as i32;
let rel = &(target_loc as i32 - offset_loc) as *const i32;

let offset_ptr = mem.contents.as_ptr().add(jump.offset_loc) as *mut u8;
ptr::copy_nonoverlapping(rel.cast::<u8>(), offset_ptr, std::mem::size_of::<i32>());
ptr::copy_nonoverlapping(rel.cast::<u8>(), offset_ptr, core::mem::size_of::<i32>());
}
}
Ok(())
Expand All @@ -1014,11 +1008,13 @@ impl JitCompiler {

pub struct JitMemory<'a> {
contents: &'a mut [u8],
layout: alloc::Layout,
#[cfg(feature = "std")]
layout: std::alloc::Layout,
offset: usize,
}

impl<'a> JitMemory<'a> {
#[cfg(feature = "std")]
pub fn new(
prog: &[u8],
helpers: &HashMap<u32, ebpf::Helper>,
Expand All @@ -1031,10 +1027,10 @@ impl<'a> JitMemory<'a> {
let contents = unsafe {
// Create a layout with the proper size and alignment.
let size = NUM_PAGES * PAGE_SIZE;
layout = alloc::Layout::from_size_align_unchecked(size, PAGE_SIZE);
layout = std::alloc::Layout::from_size_align_unchecked(size, PAGE_SIZE);

// Allocate the region of memory.
let ptr = alloc::alloc(layout);
let ptr = std::alloc::alloc(layout);
if ptr.is_null() {
return Err(Error::from(std::io::ErrorKind::OutOfMemory));
}
Expand All @@ -1059,6 +1055,40 @@ impl<'a> JitMemory<'a> {
Ok(mem)
}

#[cfg(not(feature = "std"))]
pub fn new(
prog: &[u8],
executable_memory: &'a mut [u8],
helpers: &HashMap<u32, ebpf::Helper>,
use_mbuff: bool,
update_data_ptr: bool,
) -> Result<JitMemory<'a>, Error> {
let contents = executable_memory;
if contents.len() < NUM_PAGES * PAGE_SIZE {
return Err(Error::new(
ErrorKind::Other,
"Executable memory is too small",
));
}
if contents.as_ptr() as usize % PAGE_SIZE != 0 {
return Err(Error::new(
ErrorKind::Other,
"Executable memory is not aligned",
));
}

let mut mem = JitMemory {
contents,
offset: 0,
};

let mut jit = JitCompiler::new();
jit.jit_compile(&mut mem, prog, use_mbuff, update_data_ptr, helpers)?;
jit.resolve_jumps(&mut mem)?;

Ok(mem)
}

pub fn get_prog(&self) -> MachineCode {
unsafe { mem::transmute(self.contents.as_ptr()) }
}
Expand All @@ -1078,15 +1108,16 @@ impl IndexMut<usize> for JitMemory<'_> {
}
}

#[cfg(feature = "std")]
impl Drop for JitMemory<'_> {
fn drop(&mut self) {
unsafe {
alloc::dealloc(self.contents.as_mut_ptr(), self.layout);
std::alloc::dealloc(self.contents.as_mut_ptr(), self.layout);
}
}
}

impl std::fmt::Debug for JitMemory<'_> {
impl core::fmt::Debug for JitMemory<'_> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatterError> {
fmt.write_str("JIT contents: [")?;
fmt.write_str(" ] | ")?;
Expand Down
Loading
Loading