#![doc(html_logo_url = "https://raw.githubusercontent.com/qmonnet/rbpf/master/misc/rbpf.png",
html_favicon_url = "https://raw.githubusercontent.com/qmonnet/rbpf/master/misc/rbpf.ico")]
#![warn(missing_docs)]
#![allow(unused_mut)]
#![allow(renamed_and_removed_lints)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names, single_match, cast_lossless, doc_markdown, match_same_arms, unreadable_literal))]
extern crate byteorder;
extern crate combine;
extern crate time;
use std::u32;
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use byteorder::{ByteOrder, LittleEndian};
pub mod assembler;
pub mod disassembler;
pub mod ebpf;
pub mod helpers;
pub mod insn_builder;
mod asm_parser;
#[cfg(not(windows))]
mod jit;
mod verifier;
pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;
pub type Helper = fn (u64, u64, u64, u64, u64) -> u64;
pub type JitProgram = unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64;
struct MetaBuff {
data_offset: usize,
data_end_offset: usize,
buffer: Vec<u8>,
}
pub struct EbpfVmMbuff<'a> {
prog: Option<&'a [u8]>,
verifier: Verifier,
jit: Option<JitProgram>,
helpers: HashMap<u32, ebpf::Helper>,
}
impl<'a> EbpfVmMbuff<'a> {
pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmMbuff<'a>, Error> {
if let Some(prog) = prog {
verifier::check(prog)?;
}
Ok(EbpfVmMbuff {
prog: prog,
verifier: verifier::check,
jit: None,
helpers: HashMap::new(),
})
}
pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
(self.verifier)(prog)?;
self.prog = Some(prog);
Ok(())
}
pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
if let Some(prog) = self.prog {
verifier(prog)?;
}
self.verifier = verifier;
Ok(())
}
pub fn register_helper(&mut self, key: u32, function: Helper) -> Result<(), Error> {
self.helpers.insert(key, function);
Ok(())
}
#[allow(unknown_lints)]
#[allow(cyclomatic_complexity)]
pub fn execute_program(&self, mem: &[u8], mbuff: &[u8]) -> Result<u64, Error> {
const U32MAX: u64 = u32::MAX as u64;
let prog = match self.prog {
Some(prog) => prog,
None => Err(Error::new(ErrorKind::Other,
"Error: No program set, call prog_set() to load one"))?,
};
let stack = vec![0u8;ebpf::STACK_SIZE];
let mut reg: [u64;11] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, stack.as_ptr() as u64 + stack.len() as u64
];
if !mbuff.is_empty() {
reg[1] = mbuff.as_ptr() as u64;
}
else if !mem.is_empty() {
reg[1] = mem.as_ptr() as u64;
}
let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, mbuff, mem, &stack)
};
let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, mbuff, mem, &stack)
};
let mut insn_ptr:usize = 0;
while insn_ptr * ebpf::INSN_SIZE < prog.len() {
let insn = ebpf::get_insn(prog, insn_ptr);
insn_ptr += 1;
let _dst = insn.dst as usize;
let _src = insn.src as usize;
match insn.opc {
ebpf::LD_ABS_B => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u8;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_ABS_H => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u16;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_ABS_W => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u32;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_ABS_DW => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u64;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_IND_B => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u8;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_IND_H => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u16;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_IND_W => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u32;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_IND_DW => reg[0] = unsafe {
let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u64;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::LD_DW_IMM => {
let next_insn = ebpf::get_insn(prog, insn_ptr);
insn_ptr += 1;
reg[_dst] = ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32);
},
ebpf::LD_B_REG => reg[_dst] = unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u8;
check_mem_load(x as u64, 1, insn_ptr)?;
*x as u64
},
ebpf::LD_H_REG => reg[_dst] = unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u16;
check_mem_load(x as u64, 2, insn_ptr)?;
*x as u64
},
ebpf::LD_W_REG => reg[_dst] = unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u32;
check_mem_load(x as u64, 4, insn_ptr)?;
*x as u64
},
ebpf::LD_DW_REG => reg[_dst] = unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u64;
check_mem_load(x as u64, 8, insn_ptr)?;
*x as u64
},
ebpf::ST_B_IMM => unsafe {
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
check_mem_store(x as u64, 1, insn_ptr)?;
*x = insn.imm as u8;
},
ebpf::ST_H_IMM => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
check_mem_store(x as u64, 2, insn_ptr)?;
*x = insn.imm as u16;
},
ebpf::ST_W_IMM => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
check_mem_store(x as u64, 4, insn_ptr)?;
*x = insn.imm as u32;
},
ebpf::ST_DW_IMM => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
check_mem_store(x as u64, 8, insn_ptr)?;
*x = insn.imm as u64;
},
ebpf::ST_B_REG => unsafe {
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
check_mem_store(x as u64, 1, insn_ptr)?;
*x = reg[_src] as u8;
},
ebpf::ST_H_REG => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
check_mem_store(x as u64, 2, insn_ptr)?;
*x = reg[_src] as u16;
},
ebpf::ST_W_REG => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
check_mem_store(x as u64, 4, insn_ptr)?;
*x = reg[_src] as u32;
},
ebpf::ST_DW_REG => unsafe {
#[allow(cast_ptr_alignment)]
let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
check_mem_store(x as u64, 8, insn_ptr)?;
*x = reg[_src] as u64;
},
ebpf::ST_W_XADD => unimplemented!(),
ebpf::ST_DW_XADD => unimplemented!(),
ebpf::ADD32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_add(insn.imm) as u64, ebpf::ADD32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_add(reg[_src] as i32) as u64, ebpf::SUB32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_sub(insn.imm) as u64,
ebpf::SUB32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_sub(reg[_src] as i32) as u64,
ebpf::MUL32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_mul(insn.imm) as u64,
ebpf::MUL32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_mul(reg[_src] as i32) as u64,
ebpf::DIV32_IMM => reg[_dst] = (reg[_dst] as u32 / insn.imm as u32) as u64,
ebpf::DIV32_REG => {
if reg[_src] == 0 {
Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
}
reg[_dst] = (reg[_dst] as u32 / reg[_src] as u32) as u64;
},
ebpf::OR32_IMM => reg[_dst] = (reg[_dst] as u32 | insn.imm as u32) as u64,
ebpf::OR32_REG => reg[_dst] = (reg[_dst] as u32 | reg[_src] as u32) as u64,
ebpf::AND32_IMM => reg[_dst] = (reg[_dst] as u32 & insn.imm as u32) as u64,
ebpf::AND32_REG => reg[_dst] = (reg[_dst] as u32 & reg[_src] as u32) as u64,
ebpf::LSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shl(insn.imm as u32) as u64,
ebpf::LSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shl(reg[_src] as u32) as u64,
ebpf::RSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shr(insn.imm as u32) as u64,
ebpf::RSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shr(reg[_src] as u32) as u64,
ebpf::NEG32 => { reg[_dst] = (reg[_dst] as i32).wrapping_neg() as u64; reg[_dst] &= U32MAX; },
ebpf::MOD32_IMM => reg[_dst] = (reg[_dst] as u32 % insn.imm as u32) as u64,
ebpf::MOD32_REG => {
if reg[_src] == 0 {
Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
}
reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64;
},
ebpf::XOR32_IMM => reg[_dst] = (reg[_dst] as u32 ^ insn.imm as u32) as u64,
ebpf::XOR32_REG => reg[_dst] = (reg[_dst] as u32 ^ reg[_src] as u32) as u64,
ebpf::MOV32_IMM => reg[_dst] = insn.imm as u64,
ebpf::MOV32_REG => reg[_dst] = (reg[_src] as u32) as u64,
ebpf::ARSH32_IMM => { reg[_dst] = (reg[_dst] as i32).wrapping_shr(insn.imm as u32) as u64; reg[_dst] &= U32MAX; },
ebpf::ARSH32_REG => { reg[_dst] = (reg[_dst] as i32).wrapping_shr(reg[_src] as u32) as u64; reg[_dst] &= U32MAX; },
ebpf::LE => {
reg[_dst] = match insn.imm {
16 => (reg[_dst] as u16).to_le() as u64,
32 => (reg[_dst] as u32).to_le() as u64,
64 => reg[_dst].to_le(),
_ => unreachable!(),
};
},
ebpf::BE => {
reg[_dst] = match insn.imm {
16 => (reg[_dst] as u16).to_be() as u64,
32 => (reg[_dst] as u32).to_be() as u64,
64 => reg[_dst].to_be(),
_ => unreachable!(),
};
},
ebpf::ADD64_IMM => reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
ebpf::ADD64_REG => reg[_dst] = reg[_dst].wrapping_add(reg[_src]),
ebpf::SUB64_IMM => reg[_dst] = reg[_dst].wrapping_sub(insn.imm as u64),
ebpf::SUB64_REG => reg[_dst] = reg[_dst].wrapping_sub(reg[_src]),
ebpf::MUL64_IMM => reg[_dst] = reg[_dst].wrapping_mul(insn.imm as u64),
ebpf::MUL64_REG => reg[_dst] = reg[_dst].wrapping_mul(reg[_src]),
ebpf::DIV64_IMM => reg[_dst] /= insn.imm as u64,
ebpf::DIV64_REG => {
if reg[_src] == 0 {
Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
}
reg[_dst] /= reg[_src];
},
ebpf::OR64_IMM => reg[_dst] |= insn.imm as u64,
ebpf::OR64_REG => reg[_dst] |= reg[_src],
ebpf::AND64_IMM => reg[_dst] &= insn.imm as u64,
ebpf::AND64_REG => reg[_dst] &= reg[_src],
ebpf::LSH64_IMM => reg[_dst] <<= insn.imm as u64,
ebpf::LSH64_REG => reg[_dst] <<= reg[_src],
ebpf::RSH64_IMM => reg[_dst] >>= insn.imm as u64,
ebpf::RSH64_REG => reg[_dst] >>= reg[_src],
ebpf::NEG64 => reg[_dst] = -(reg[_dst] as i64) as u64,
ebpf::MOD64_IMM => reg[_dst] %= insn.imm as u64,
ebpf::MOD64_REG => {
if reg[_src] == 0 {
Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
}
reg[_dst] %= reg[_src];
},
ebpf::XOR64_IMM => reg[_dst] ^= insn.imm as u64,
ebpf::XOR64_REG => reg[_dst] ^= reg[_src],
ebpf::MOV64_IMM => reg[_dst] = insn.imm as u64,
ebpf::MOV64_REG => reg[_dst] = reg[_src],
ebpf::ARSH64_IMM => reg[_dst] = (reg[_dst] as i64 >> insn.imm) as u64,
ebpf::ARSH64_REG => reg[_dst] = (reg[_dst] as i64 >> reg[_src]) as u64,
ebpf::JA => insn_ptr = (insn_ptr as i16 + insn.off) as usize,
ebpf::JEQ_IMM => if reg[_dst] == insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JEQ_REG => if reg[_dst] == reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JGT_IMM => if reg[_dst] > insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JGT_REG => if reg[_dst] > reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JGE_IMM => if reg[_dst] >= insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JGE_REG => if reg[_dst] >= reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JLT_IMM => if reg[_dst] < insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JLT_REG => if reg[_dst] < reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JLE_IMM => if reg[_dst] <= insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JLE_REG => if reg[_dst] <= reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSET_IMM => if reg[_dst] & insn.imm as u64 != 0 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSET_REG => if reg[_dst] & reg[_src] != 0 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JNE_IMM => if reg[_dst] != insn.imm as u64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JNE_REG => if reg[_dst] != reg[_src] { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSGT_IMM => if reg[_dst] as i64 > insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSGT_REG => if reg[_dst] as i64 > reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSGE_IMM => if reg[_dst] as i64 >= insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSGE_REG => if reg[_dst] as i64 >= reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSLT_IMM => if (reg[_dst] as i64) < insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSLT_REG => if (reg[_dst] as i64) < reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSLE_IMM => if (reg[_dst] as i64) <= insn.imm as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::JSLE_REG => if (reg[_dst] as i64) <= reg[_src] as i64 { insn_ptr = (insn_ptr as i16 + insn.off) as usize; },
ebpf::CALL => if let Some(function) = self.helpers.get(&(insn.imm as u32)) {
reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]);
} else {
Err(Error::new(ErrorKind::Other, format!("Error: unknown helper function (id: {:#x})", insn.imm as u32)))?;
},
ebpf::TAIL_CALL => unimplemented!(),
ebpf::EXIT => return Ok(reg[0]),
_ => unreachable!()
}
}
unreachable!()
}
fn check_mem(addr: u64, len: usize, access_type: &str, insn_ptr: usize,
mbuff: &[u8], mem: &[u8], stack: &[u8]) -> Result<(), Error> {
if mbuff.as_ptr() as u64 <= addr && addr + len as u64 <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
return Ok(())
}
if mem.as_ptr() as u64 <= addr && addr + len as u64 <= mem.as_ptr() as u64 + mem.len() as u64 {
return Ok(())
}
if stack.as_ptr() as u64 <= addr && addr + len as u64 <= stack.as_ptr() as u64 + stack.len() as u64 {
return Ok(())
}
Err(Error::new(ErrorKind::Other, format!(
"Error: out of bounds memory {} (insn #{:?}), addr {:#x}, size {:?}\nmbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
access_type, insn_ptr, addr, len,
mbuff.as_ptr() as u64, mbuff.len(),
mem.as_ptr() as u64, mem.len(),
stack.as_ptr() as u64, stack.len()
)))
}
#[cfg(not(windows))]
pub fn jit_compile(&mut self) -> Result<(), Error> {
let prog = match self.prog {
Some(prog) => prog,
None => Err(Error::new(ErrorKind::Other, "Error: No program set, call prog_set() to load one"))?,
};
self.jit = Some(jit::compile(prog, &self.helpers, true, false)?);
Ok(())
}
pub unsafe fn execute_program_jit(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> Result<u64, Error> {
let mem_ptr = match mem.len() {
0 => std::ptr::null_mut(),
_ => mem.as_ptr() as *mut u8
};
match self.jit {
Some(jit) => Ok(jit(mbuff.as_ptr() as *mut u8, mbuff.len(), mem_ptr, mem.len(), 0, 0)),
None => Err(Error::new(ErrorKind::Other,
"Error: program has not been JIT-compiled")),
}
}
}
pub struct EbpfVmFixedMbuff<'a> {
parent: EbpfVmMbuff<'a>,
mbuff: MetaBuff,
}
impl<'a> EbpfVmFixedMbuff<'a> {
pub fn new(prog: Option<&'a [u8]>, data_offset: usize, data_end_offset: usize) -> Result<EbpfVmFixedMbuff<'a>, Error> {
let parent = EbpfVmMbuff::new(prog)?;
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 mbuff = MetaBuff {
data_offset: data_offset,
data_end_offset: data_end_offset,
buffer: buffer,
};
Ok(EbpfVmFixedMbuff {
parent: parent,
mbuff: mbuff,
})
}
pub fn set_program(&mut self, prog: &'a [u8], data_offset: usize, data_end_offset: usize) -> Result<(), Error> {
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)];
self.mbuff.buffer = buffer;
self.mbuff.data_offset = data_offset;
self.mbuff.data_end_offset = data_end_offset;
self.parent.set_program(prog)?;
Ok(())
}
pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
self.parent.set_verifier(verifier)
}
pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
self.parent.register_helper(key, function)
}
pub fn execute_program(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
let l = self.mbuff.buffer.len();
if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
}
LittleEndian::write_u64(&mut self.mbuff.buffer[(self.mbuff.data_offset) .. ], mem.as_ptr() as u64);
LittleEndian::write_u64(&mut self.mbuff.buffer[(self.mbuff.data_end_offset) .. ], mem.as_ptr() as u64 + mem.len() as u64);
self.parent.execute_program(mem, &self.mbuff.buffer)
}
#[cfg(not(windows))]
pub fn jit_compile(&mut self) -> Result<(), Error> {
let prog = match self.parent.prog {
Some(prog) => prog,
None => Err(Error::new(ErrorKind::Other, "Error: No program set, call prog_set() to load one"))?,
};
self.parent.jit = Some(jit::compile(prog, &self.parent.helpers, true, true)?);
Ok(())
}
pub unsafe fn execute_program_jit(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
let mem_ptr = match mem.len() {
0 => std::ptr::null_mut(),
_ => mem.as_ptr() as *mut u8
};
match self.parent.jit {
Some(jit) => Ok(jit(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::new(ErrorKind::Other,
"Error: program has not been JIT-compiled"))
}
}
}
pub struct EbpfVmRaw<'a> {
parent: EbpfVmMbuff<'a>,
}
impl<'a> EbpfVmRaw<'a> {
pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmRaw<'a>, Error> {
let parent = EbpfVmMbuff::new(prog)?;
Ok(EbpfVmRaw {
parent: parent,
})
}
pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
self.parent.set_program(prog)?;
Ok(())
}
pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
self.parent.set_verifier(verifier)
}
pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
self.parent.register_helper(key, function)
}
pub fn execute_program(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
self.parent.execute_program(mem, &[])
}
#[cfg(not(windows))]
pub fn jit_compile(&mut self) -> Result<(), Error> {
let prog = match self.parent.prog {
Some(prog) => prog,
None => Err(Error::new(ErrorKind::Other,
"Error: No program set, call prog_set() to load one"))?,
};
self.parent.jit = Some(jit::compile(prog, &self.parent.helpers, false, false)?);
Ok(())
}
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)
}
}
pub struct EbpfVmNoData<'a> {
parent: EbpfVmRaw<'a>,
}
impl<'a> EbpfVmNoData<'a> {
pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmNoData<'a>, Error> {
let parent = EbpfVmRaw::new(prog)?;
Ok(EbpfVmNoData {
parent: parent,
})
}
pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
self.parent.set_program(prog)?;
Ok(())
}
pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
self.parent.set_verifier(verifier)
}
pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
self.parent.register_helper(key, function)
}
#[cfg(not(windows))]
pub fn jit_compile(&mut self) -> Result<(), Error> {
self.parent.jit_compile()
}
pub fn execute_program(&self) -> Result<(u64), Error> {
self.parent.execute_program(&mut [])
}
pub unsafe fn execute_program_jit(&self) -> Result<(u64), Error> {
self.parent.execute_program_jit(&mut [])
}
}