Skip to content

Commit 404ccd0

Browse files
notgullqmonnet
authored andcommitted
feat: Reduce dependency on libc
I am attempting to reduce the dependence on libc in my indirect dependencies. While looking at this crate I noticed some low-hanging fruit that can be very easily replaced with libc. - The rand() function can be re-implemented as a simple Wyrand seeded by the thread ID and the current time. - libc::memcpy is used at a point where it can be replaced with ptr::copy_nonoverlapping. - libc is used for memory allocation at a point where std::alloc can be used instead. So I use this. I'm not too familiar with this codebase, so if any of these replacements are incorrect, please let me know. The only leftover libc call is mprotect(). Signed-off-by: John Nunley <[email protected]>
1 parent cfb363c commit 404ccd0

File tree

2 files changed

+55
-37
lines changed

2 files changed

+55
-37
lines changed

src/helpers.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
1717
//! respect this convention.
1818
19-
#[cfg(feature = "std")]
20-
extern crate libc;
21-
2219
use crate::lib::*;
2320

2421
// Helpers associated to kernel helpers
@@ -243,30 +240,39 @@ pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u
243240
/// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
244241
/// 5 are unused.
245242
///
246-
/// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
247-
/// helper is used.
248-
///
249-
/// # Examples
250-
///
251-
/// ```
252-
/// extern crate libc;
253-
/// extern crate rbpf;
254-
/// extern crate time;
255-
///
256-
/// unsafe {
257-
/// libc::srand(time::precise_time_ns() as u32)
258-
/// }
259-
///
260-
/// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
261-
/// assert!(3 <= n && n <= 6);
262-
/// ```
243+
/// This does not rely on `libc::rand()` and therefore can be called without `libc::srand()`.
263244
#[allow(dead_code)]
264245
#[allow(unused_variables)]
265246
#[cfg(feature = "std")]
266247
pub fn rand (min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
267-
let mut n = unsafe {
268-
(libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64
269-
};
248+
use std::cell::Cell;
249+
use std::collections::hash_map::DefaultHasher;
250+
use std::hash::{Hash, Hasher};
251+
use std::thread;
252+
use std::time::Instant;
253+
254+
// Constants for WyRand taken from: https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h#L151
255+
const WY_CONST_0: u64 = 0x2d35_8dcc_aa6c_78a5;
256+
const WY_CONST_1: u64 = 0x8bb8_4b93_962e_acc9;
257+
258+
std::thread_local! {
259+
static RNG: Cell<u64> = {
260+
// Seed the RNG with the thread ID and the current time.
261+
let mut hasher = DefaultHasher::new();
262+
Instant::now().hash(&mut hasher);
263+
thread::current().id().hash(&mut hasher);
264+
Cell::new(hasher.finish())
265+
};
266+
}
267+
268+
// Run one round of WyRand.
269+
let mut n = RNG.with(|rng| {
270+
let s = rng.get().wrapping_add(WY_CONST_0);
271+
rng.set(s);
272+
let t = u128::from(s) * u128::from(s ^ WY_CONST_1);
273+
(t as u64) ^ (t >> 64) as u64
274+
});
275+
270276
if min < max {
271277
n = n % (max + 1 - min) + min;
272278
};

src/jit.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
// Copyright 2016 6WIND S.A. <[email protected]>
66
// (Translation to Rust, MetaBuff addition)
77

8+
use std::alloc;
89
use std::mem;
910
use std::collections::HashMap;
1011
use std::fmt::Formatter;
1112
use std::fmt::Error as FormatterError;
1213
use std::io::{Error, ErrorKind};
1314
use std::ops::{Index, IndexMut};
15+
use std::ptr;
1416

1517
use ebpf;
1618

@@ -931,10 +933,8 @@ impl JitCompiler {
931933
let offset_loc = jump.offset_loc as i32 + std::mem::size_of::<i32>() as i32;
932934
let rel = &(target_loc as i32 - offset_loc) as *const i32;
933935

934-
let offset_ptr = mem.contents.as_ptr().add(jump.offset_loc);
935-
936-
libc::memcpy(offset_ptr as *mut libc::c_void, rel as *const libc::c_void,
937-
std::mem::size_of::<i32>());
936+
let offset_ptr = mem.contents.as_ptr().add(jump.offset_loc) as *mut u8;
937+
ptr::copy_nonoverlapping(rel.cast::<u8>(), offset_ptr, std::mem::size_of::<i32>());
938938
}
939939
}
940940
Ok(())
@@ -943,25 +943,37 @@ impl JitCompiler {
943943

944944
pub struct JitMemory<'a> {
945945
contents: &'a mut [u8],
946+
layout: alloc::Layout,
946947
offset: usize,
947948
}
948949

949950
impl<'a> JitMemory<'a> {
950951
pub fn new(prog: &[u8], helpers: &HashMap<u32, ebpf::Helper>, use_mbuff: bool,
951952
update_data_ptr: bool) -> Result<JitMemory<'a>, Error> {
952-
let contents: &mut[u8];
953-
let mut raw: mem::MaybeUninit<*mut libc::c_void> = mem::MaybeUninit::uninit();
954-
unsafe {
953+
let layout;
954+
955+
// Allocate the appropriately sized memory.
956+
let contents = unsafe {
957+
// Create a layout with the proper size and alignment.
955958
let size = NUM_PAGES * PAGE_SIZE;
956-
libc::posix_memalign(raw.as_mut_ptr(), PAGE_SIZE, size);
957-
libc::mprotect(*raw.as_mut_ptr(), size, libc::PROT_EXEC | libc::PROT_READ | libc::PROT_WRITE);
958-
std::ptr::write_bytes(*raw.as_mut_ptr(), 0xc3, size); // for now, prepopulate with 'RET' calls
959-
contents = std::slice::from_raw_parts_mut(*raw.as_mut_ptr() as *mut u8, NUM_PAGES * PAGE_SIZE);
960-
raw.assume_init();
961-
}
959+
layout = alloc::Layout::from_size_align_unchecked(size, PAGE_SIZE);
960+
961+
// Allocate the region of memory.
962+
let ptr = alloc::alloc(layout);
963+
if ptr.is_null() {
964+
return Err(Error::from(std::io::ErrorKind::OutOfMemory));
965+
}
966+
967+
// Protect it.
968+
libc::mprotect(ptr.cast(), size, libc::PROT_EXEC | libc::PROT_WRITE);
969+
970+
// Convert to a slice.
971+
std::slice::from_raw_parts_mut(ptr, size)
972+
};
962973

963974
let mut mem = JitMemory {
964975
contents,
976+
layout,
965977
offset: 0,
966978
};
967979

@@ -994,7 +1006,7 @@ impl<'a> IndexMut<usize> for JitMemory<'a> {
9941006
impl<'a> Drop for JitMemory<'a> {
9951007
fn drop(&mut self) {
9961008
unsafe {
997-
libc::free(self.contents.as_mut_ptr() as *mut libc::c_void);
1009+
alloc::dealloc(self.contents.as_mut_ptr(), self.layout);
9981010
}
9991011
}
10001012
}

0 commit comments

Comments
 (0)