|
@@ -33,7 +33,7 @@ pub mod disassembler;
|
|
struct MetaBuff {
|
|
struct MetaBuff {
|
|
data_offset: usize,
|
|
data_offset: usize,
|
|
data_end_offset: usize,
|
|
data_end_offset: usize,
|
|
- buffer: std::vec::Vec<u8>,
|
|
|
|
|
|
+ buffer: Vec<u8>,
|
|
}
|
|
}
|
|
|
|
|
|
/// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
|
|
/// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
|
|
@@ -69,7 +69,7 @@ struct MetaBuff {
|
|
/// assert_eq!(res, 0x2211);
|
|
/// assert_eq!(res, 0x2211);
|
|
/// ```
|
|
/// ```
|
|
pub struct EbpfVmMbuff<'a> {
|
|
pub struct EbpfVmMbuff<'a> {
|
|
- prog: &'a std::vec::Vec<u8>,
|
|
|
|
|
|
+ prog: &'a [u8],
|
|
jit: (unsafe fn (*mut u8, usize, *mut u8, usize, usize, usize) -> u64),
|
|
jit: (unsafe fn (*mut u8, usize, *mut u8, usize, usize, usize) -> u64),
|
|
helpers: HashMap<u32, fn (u64, u64, u64, u64, u64) -> u64>,
|
|
helpers: HashMap<u32, fn (u64, u64, u64, u64, u64) -> u64>,
|
|
}
|
|
}
|
|
@@ -95,12 +95,11 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
/// // Instantiate a VM.
|
|
/// // Instantiate a VM.
|
|
/// let mut vm = rbpf::EbpfVmMbuff::new(&prog);
|
|
/// let mut vm = rbpf::EbpfVmMbuff::new(&prog);
|
|
/// ```
|
|
/// ```
|
|
- pub fn new(prog: &'a std::vec::Vec<u8>) -> EbpfVmMbuff<'a> {
|
|
|
|
|
|
+ pub fn new(prog: &'a [u8]) -> EbpfVmMbuff<'a> {
|
|
verifier::check(prog);
|
|
verifier::check(prog);
|
|
|
|
|
|
- #[allow(unused_variables)]
|
|
|
|
- fn no_jit(foo: *mut u8, foo_len: usize, bar: *mut u8, bar_len: usize,
|
|
|
|
- nodata_offset: usize, nodata_end_offset: usize) -> u64 {
|
|
|
|
|
|
+ fn no_jit(_mbuff: *mut u8, _len: usize, _mem: *mut u8, _mem_len: usize,
|
|
|
|
+ _nodata_offset: usize, _nodata_end_offset: usize) -> u64 {
|
|
panic!("Error: program has not been JIT-compiled");
|
|
panic!("Error: program has not been JIT-compiled");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -134,7 +133,7 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
/// let mut vm = rbpf::EbpfVmMbuff::new(&prog1);
|
|
/// let mut vm = rbpf::EbpfVmMbuff::new(&prog1);
|
|
/// vm.set_prog(&prog2);
|
|
/// vm.set_prog(&prog2);
|
|
/// ```
|
|
/// ```
|
|
- pub fn set_prog(&mut self, prog: &'a std::vec::Vec<u8>) {
|
|
|
|
|
|
+ pub fn set_prog(&mut self, prog: &'a [u8]) {
|
|
verifier::check(prog);
|
|
verifier::check(prog);
|
|
self.prog = prog;
|
|
self.prog = prog;
|
|
}
|
|
}
|
|
@@ -220,7 +219,7 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
/// let res = vm.prog_exec(&mut mem, &mut mbuff);
|
|
/// let res = vm.prog_exec(&mut mem, &mut mbuff);
|
|
/// assert_eq!(res, 0x2211);
|
|
/// assert_eq!(res, 0x2211);
|
|
/// ```
|
|
/// ```
|
|
- pub fn prog_exec(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
|
|
+ pub fn prog_exec(&self, mem: &[u8], mbuff: &[u8]) -> u64 {
|
|
const U32MAX: u64 = u32::MAX as u64;
|
|
const U32MAX: u64 = u32::MAX as u64;
|
|
|
|
|
|
let stack = vec![0u8;ebpf::STACK_SIZE];
|
|
let stack = vec![0u8;ebpf::STACK_SIZE];
|
|
@@ -237,10 +236,10 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
}
|
|
}
|
|
|
|
|
|
let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
|
|
let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
|
|
- EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, &mbuff, &mem, &stack);
|
|
|
|
|
|
+ EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, mbuff, mem, &stack);
|
|
};
|
|
};
|
|
let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
|
|
let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
|
|
- EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, &mbuff, &mem, &stack);
|
|
|
|
|
|
+ EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, mbuff, mem, &stack);
|
|
};
|
|
};
|
|
|
|
|
|
// Loop on instructions
|
|
// Loop on instructions
|
|
@@ -464,7 +463,7 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
}
|
|
}
|
|
|
|
|
|
fn check_mem(addr: u64, len: usize, access_type: &str, insn_ptr: usize,
|
|
fn check_mem(addr: u64, len: usize, access_type: &str, insn_ptr: usize,
|
|
- mbuff: &std::vec::Vec<u8>, mem: &std::vec::Vec<u8>, stack: &std::vec::Vec<u8>) {
|
|
|
|
|
|
+ mbuff: &[u8], mem: &[u8], stack: &[u8]) {
|
|
if mbuff.as_ptr() as u64 <= addr && addr + len as u64 <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
|
|
if mbuff.as_ptr() as u64 <= addr && addr + len as u64 <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
@@ -509,7 +508,7 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
/// vm.jit_compile();
|
|
/// vm.jit_compile();
|
|
/// ```
|
|
/// ```
|
|
pub fn jit_compile(&mut self) {
|
|
pub fn jit_compile(&mut self) {
|
|
- self.jit = jit::compile(&self.prog, &self.helpers, true, false);
|
|
|
|
|
|
+ self.jit = jit::compile(self.prog, &self.helpers, true, false);
|
|
}
|
|
}
|
|
|
|
|
|
/// Execute the previously JIT-compiled program, with the given packet data and metadata
|
|
/// Execute the previously JIT-compiled program, with the given packet data and metadata
|
|
@@ -566,7 +565,7 @@ impl<'a> EbpfVmMbuff<'a> {
|
|
/// assert_eq!(res, 0x2211);
|
|
/// assert_eq!(res, 0x2211);
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
/// ```
|
|
- pub unsafe fn prog_exec_jit(&self, mem: &mut std::vec::Vec<u8>, mbuff: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
|
|
+ pub unsafe fn prog_exec_jit(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> u64 {
|
|
// If packet data is empty, do not send the address of an empty vector; send a null
|
|
// If packet data is empty, do not send the address of an empty vector; send a null
|
|
// pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
|
|
// pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
|
|
// packet should not happen in the kernel; anyway the verifier would prevent the use of
|
|
// packet should not happen in the kernel; anyway the verifier would prevent the use of
|
|
@@ -679,7 +678,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
/// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
|
|
/// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
|
|
/// let mut vm = rbpf::EbpfVmFixedMbuff::new(&prog, 0x40, 0x50);
|
|
/// let mut vm = rbpf::EbpfVmFixedMbuff::new(&prog, 0x40, 0x50);
|
|
/// ```
|
|
/// ```
|
|
- pub fn new(prog: &'a std::vec::Vec<u8>, data_offset: usize, data_end_offset: usize) -> EbpfVmFixedMbuff<'a> {
|
|
|
|
|
|
+ pub fn new(prog: &'a [u8], data_offset: usize, data_end_offset: usize) -> EbpfVmFixedMbuff<'a> {
|
|
let parent = EbpfVmMbuff::new(prog);
|
|
let parent = EbpfVmMbuff::new(prog);
|
|
let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
|
|
let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
|
|
let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
|
|
let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
|
|
@@ -730,7 +729,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// assert_eq!(res, 0x27);
|
|
/// assert_eq!(res, 0x27);
|
|
/// ```
|
|
/// ```
|
|
- pub fn set_prog(&mut self, prog: &'a std::vec::Vec<u8>, data_offset: usize, data_end_offset: usize) {
|
|
|
|
|
|
+ pub fn set_prog(&mut self, prog: &'a [u8], data_offset: usize, data_end_offset: usize) {
|
|
let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
|
|
let get_buff_len = | x: usize, y: usize | if x >= y { x + 8 } else { y + 8 };
|
|
let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
|
|
let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
|
|
self.mbuff.buffer = buffer;
|
|
self.mbuff.buffer = buffer;
|
|
@@ -821,7 +820,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// assert_eq!(res, 0xdd);
|
|
/// assert_eq!(res, 0xdd);
|
|
/// ```
|
|
/// ```
|
|
- pub fn prog_exec(&mut self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
|
|
+ pub fn prog_exec(&mut self, mem: &'a mut [u8]) -> u64 {
|
|
let l = self.mbuff.buffer.len();
|
|
let l = self.mbuff.buffer.len();
|
|
// Can this ever happen? Probably not, should be ensured at mbuff creation.
|
|
// Can this ever happen? Probably not, should be ensured at mbuff creation.
|
|
if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
|
|
if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
|
|
@@ -834,7 +833,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
*data = mem.as_ptr() as u64;
|
|
*data = mem.as_ptr() as u64;
|
|
*data_end = mem.as_ptr() as u64 + mem.len() as u64;
|
|
*data_end = mem.as_ptr() as u64 + mem.len() as u64;
|
|
}
|
|
}
|
|
- self.parent.prog_exec(mem, &mut self.mbuff.buffer)
|
|
|
|
|
|
+ self.parent.prog_exec(mem, &self.mbuff.buffer)
|
|
}
|
|
}
|
|
|
|
|
|
/// JIT-compile the loaded program. No argument required for this.
|
|
/// JIT-compile the loaded program. No argument required for this.
|
|
@@ -866,7 +865,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
/// vm.jit_compile();
|
|
/// vm.jit_compile();
|
|
/// ```
|
|
/// ```
|
|
pub fn jit_compile(&mut self) {
|
|
pub fn jit_compile(&mut self) {
|
|
- self.parent.jit = jit::compile(&self.parent.prog, &self.parent.helpers, true, true);
|
|
|
|
|
|
+ self.parent.jit = jit::compile(self.parent.prog, &self.parent.helpers, true, true);
|
|
}
|
|
}
|
|
|
|
|
|
/// Execute the previously JIT-compiled program, with the given packet data, in a manner very
|
|
/// Execute the previously JIT-compiled program, with the given packet data, in a manner very
|
|
@@ -919,7 +918,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
|
|
/// ```
|
|
/// ```
|
|
// This struct redefines the `prog_exec_jit()` function, in order to pass the offsets
|
|
// This struct redefines the `prog_exec_jit()` function, in order to pass the offsets
|
|
// associated with the fixed mbuff.
|
|
// associated with the fixed mbuff.
|
|
- pub unsafe fn prog_exec_jit(&mut self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
|
|
+ pub unsafe fn prog_exec_jit(&mut self, mem: &'a mut [u8]) -> u64 {
|
|
// If packet data is empty, do not send the address of an empty vector; send a null
|
|
// If packet data is empty, do not send the address of an empty vector; send a null
|
|
// pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
|
|
// pointer (zero value) as first argument instead, as this is uBPF's behavior (empty
|
|
// packet should not happen in the kernel; anyway the verifier would prevent the use of
|
|
// packet should not happen in the kernel; anyway the verifier would prevent the use of
|
|
@@ -982,7 +981,7 @@ impl<'a> EbpfVmRaw<'a> {
|
|
/// // Instantiate a VM.
|
|
/// // Instantiate a VM.
|
|
/// let vm = rbpf::EbpfVmRaw::new(&prog);
|
|
/// let vm = rbpf::EbpfVmRaw::new(&prog);
|
|
/// ```
|
|
/// ```
|
|
- pub fn new(prog: &'a std::vec::Vec<u8>) -> EbpfVmRaw<'a> {
|
|
|
|
|
|
+ pub fn new(prog: &'a [u8]) -> EbpfVmRaw<'a> {
|
|
let parent = EbpfVmMbuff::new(prog);
|
|
let parent = EbpfVmMbuff::new(prog);
|
|
EbpfVmRaw {
|
|
EbpfVmRaw {
|
|
parent: parent,
|
|
parent: parent,
|
|
@@ -1019,7 +1018,7 @@ impl<'a> EbpfVmRaw<'a> {
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// ```
|
|
/// ```
|
|
- pub fn set_prog(&mut self, prog: &'a std::vec::Vec<u8>) {
|
|
|
|
|
|
+ pub fn set_prog(&mut self, prog: &'a [u8]) {
|
|
self.parent.set_prog(prog)
|
|
self.parent.set_prog(prog)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1089,9 +1088,8 @@ impl<'a> EbpfVmRaw<'a> {
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// let res = vm.prog_exec(&mut mem);
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// ```
|
|
/// ```
|
|
- pub fn prog_exec(&self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
- let mut mbuff = vec![];
|
|
|
|
- self.parent.prog_exec(mem, &mut mbuff)
|
|
|
|
|
|
+ pub fn prog_exec(&self, mem: &'a mut [u8]) -> u64 {
|
|
|
|
+ self.parent.prog_exec(mem, &[])
|
|
}
|
|
}
|
|
|
|
|
|
/// JIT-compile the loaded program. No argument required for this.
|
|
/// JIT-compile the loaded program. No argument required for this.
|
|
@@ -1119,7 +1117,7 @@ impl<'a> EbpfVmRaw<'a> {
|
|
/// vm.jit_compile();
|
|
/// vm.jit_compile();
|
|
/// ```
|
|
/// ```
|
|
pub fn jit_compile(&mut self) {
|
|
pub fn jit_compile(&mut self) {
|
|
- self.parent.jit = jit::compile(&self.parent.prog, &self.parent.helpers, false, false);
|
|
|
|
|
|
+ self.parent.jit = jit::compile(self.parent.prog, &self.parent.helpers, false, false);
|
|
}
|
|
}
|
|
|
|
|
|
/// Execute the previously JIT-compiled program, with the given packet data, in a manner very
|
|
/// Execute the previously JIT-compiled program, with the given packet data, in a manner very
|
|
@@ -1161,7 +1159,7 @@ impl<'a> EbpfVmRaw<'a> {
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// assert_eq!(res, 0x22cc);
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
/// ```
|
|
- pub unsafe fn prog_exec_jit(&self, mem: &'a mut std::vec::Vec<u8>) -> u64 {
|
|
|
|
|
|
+ pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> u64 {
|
|
let mut mbuff = vec![];
|
|
let mut mbuff = vec![];
|
|
self.parent.prog_exec_jit(mem, &mut mbuff)
|
|
self.parent.prog_exec_jit(mem, &mut mbuff)
|
|
}
|
|
}
|
|
@@ -1231,7 +1229,7 @@ impl<'a> EbpfVmNoData<'a> {
|
|
/// // Instantiate a VM.
|
|
/// // Instantiate a VM.
|
|
/// let vm = rbpf::EbpfVmNoData::new(&prog);
|
|
/// let vm = rbpf::EbpfVmNoData::new(&prog);
|
|
/// ```
|
|
/// ```
|
|
- pub fn new(prog: &'a std::vec::Vec<u8>) -> EbpfVmNoData<'a> {
|
|
|
|
|
|
+ pub fn new(prog: &'a [u8]) -> EbpfVmNoData<'a> {
|
|
let parent = EbpfVmRaw::new(prog);
|
|
let parent = EbpfVmRaw::new(prog);
|
|
EbpfVmNoData {
|
|
EbpfVmNoData {
|
|
parent: parent,
|
|
parent: parent,
|
|
@@ -1267,7 +1265,7 @@ impl<'a> EbpfVmNoData<'a> {
|
|
/// let res = vm.prog_exec();
|
|
/// let res = vm.prog_exec();
|
|
/// assert_eq!(res, 0x1122);
|
|
/// assert_eq!(res, 0x1122);
|
|
/// ```
|
|
/// ```
|
|
- pub fn set_prog(&mut self, prog: &'a std::vec::Vec<u8>) {
|
|
|
|
|
|
+ pub fn set_prog(&mut self, prog: &'a [u8]) {
|
|
self.parent.set_prog(prog)
|
|
self.parent.set_prog(prog)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1357,7 +1355,7 @@ impl<'a> EbpfVmNoData<'a> {
|
|
/// assert_eq!(res, 0x1122);
|
|
/// assert_eq!(res, 0x1122);
|
|
/// ```
|
|
/// ```
|
|
pub fn prog_exec(&self) -> u64 {
|
|
pub fn prog_exec(&self) -> u64 {
|
|
- self.parent.prog_exec(&mut vec![])
|
|
|
|
|
|
+ self.parent.prog_exec(&mut [])
|
|
}
|
|
}
|
|
|
|
|
|
/// Execute the previously JIT-compiled program, without providing pointers to any memory area
|
|
/// Execute the previously JIT-compiled program, without providing pointers to any memory area
|
|
@@ -1395,6 +1393,6 @@ impl<'a> EbpfVmNoData<'a> {
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
/// ```
|
|
pub unsafe fn prog_exec_jit(&self) -> u64 {
|
|
pub unsafe fn prog_exec_jit(&self) -> u64 {
|
|
- self.parent.prog_exec_jit(&mut vec![])
|
|
|
|
|
|
+ self.parent.prog_exec_jit(&mut [])
|
|
}
|
|
}
|
|
}
|
|
}
|