Skip to content

Commit

Permalink
Implements new errors for libc posix_memalign (malloc) and mprotect.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Jun 15, 2021
1 parent b8c42f8 commit 6f0effe
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 19 deletions.
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ pub enum EbpfError<E: UserDefinedError> {
/// Compilation is too big to fit
#[error("Compilation exhaused text segment at instruction {0}")]
ExhausedTextSegment(usize),
/// Libc function call returned an error
#[error("Libc calling {0} {1:?} returned an error")]
LibcInvocationFailed(&'static str, Vec<String>),
/// ELF error
#[error("Verifier error: {0}")]
VerifierError(#[from] VerifierError),
Expand Down
43 changes: 28 additions & 15 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,51 @@ struct JitProgramSections {
text_section: &'static mut [u8],
}

#[cfg(not(windows))]
macro_rules! libc_error_guard {
($function:ident, $($arg:expr),*) => {
if libc::$function($($arg),*) == 0 {
Ok(())
} else {
let args = vec![$(format!("{:?}", $arg)),*];
Err(EbpfError::LibcInvocationFailed(stringify!($function), args))
}
}
}

impl JitProgramSections {
fn new(pc: usize, code_size: usize) -> Self {
fn new<E: UserDefinedError>(pc: usize, code_size: usize) -> Result<Self, EbpfError<E>> {
let _pc_loc_table_size = round_to_page_size(pc * 8);
let _code_size = round_to_page_size(code_size);
#[cfg(windows)]
{
Self {
Ok(Self {
pc_section: &mut [],
text_section: &mut [],
}
})
}
#[cfg(not(windows))]
unsafe {
let mut raw: *mut libc::c_void = std::ptr::null_mut();
libc::posix_memalign(&mut raw, PAGE_SIZE, _pc_loc_table_size + _code_size);
libc_error_guard!(posix_memalign, &mut raw, PAGE_SIZE, _pc_loc_table_size + _code_size)?;
std::ptr::write_bytes(raw, 0x00, _pc_loc_table_size);
std::ptr::write_bytes(raw.add(_pc_loc_table_size), 0xcc, _code_size); // Populate with debugger traps
Self {
Ok(Self {
pc_section: std::slice::from_raw_parts_mut(raw as *mut u64, pc),
text_section: std::slice::from_raw_parts_mut(raw.add(_pc_loc_table_size) as *mut u8, _code_size),
}
})
}
}

fn seal(&mut self) {
fn seal<E: UserDefinedError>(&mut self) -> Result<(), EbpfError<E>> {
#[cfg(not(windows))]
if !self.pc_section.is_empty() {
unsafe {
libc::mprotect(self.pc_section.as_mut_ptr() as *mut _, round_to_page_size(self.pc_section.len()), libc::PROT_READ);
libc::mprotect(self.text_section.as_mut_ptr() as *mut _, round_to_page_size(self.text_section.len()), libc::PROT_EXEC | libc::PROT_READ);
libc_error_guard!(mprotect, self.pc_section.as_mut_ptr() as *mut _, self.pc_section.len(), libc::PROT_READ)?;
libc_error_guard!(mprotect, self.text_section.as_mut_ptr() as *mut _, self.text_section.len(), libc::PROT_EXEC | libc::PROT_READ)?;
}
}
Ok(())
}
}

Expand Down Expand Up @@ -114,7 +127,7 @@ impl<E: UserDefinedError, I: InstructionMeter> PartialEq for JitProgram<E, I> {
impl<E: UserDefinedError, I: InstructionMeter> JitProgram<E, I> {
pub fn new(executable: &dyn Executable<E, I>) -> Result<Self, EbpfError<E>> {
let program = executable.get_text_bytes()?.1;
let mut jit = JitCompiler::new(program, executable.get_config());
let mut jit = JitCompiler::new::<E>(program, executable.get_config())?;
jit.compile::<E, I>(executable)?;
let main = unsafe { mem::transmute(jit.result.text_section.as_ptr()) };
Ok(Self {
Expand Down Expand Up @@ -737,7 +750,7 @@ impl std::fmt::Debug for JitCompiler {

impl JitCompiler {
// Arguments are unused on windows
fn new(_program: &[u8], _config: &Config) -> JitCompiler {
fn new<E: UserDefinedError>(_program: &[u8], _config: &Config) -> Result<Self, EbpfError<E>> {
#[cfg(windows)]
{
panic!("JIT not supported on windows");
Expand All @@ -758,16 +771,16 @@ impl JitCompiler {
};
}

JitCompiler {
result: JitProgramSections::new(pc + 1, pc * 256 + 512),
Ok(Self {
result: JitProgramSections::new::<E>(pc + 1, pc * 256 + 512)?,
pc_section_jumps: vec![],
text_section_jumps: vec![],
offset_in_text_section: 0,
pc: 0,
program_vm_addr: 0,
handler_anchors: HashMap::new(),
config: *_config,
}
})
}

fn compile<E: UserDefinedError, I: InstructionMeter>(&mut self,
Expand Down Expand Up @@ -1118,7 +1131,7 @@ impl JitCompiler {

self.generate_epilogue::<E>()?;
self.resolve_jumps();
self.result.seal();
self.result.seal()?;

Ok(())
}
Expand Down
8 changes: 4 additions & 4 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ pub const SYSCALL_CONTEXT_OBJECTS_OFFSET: usize = 6;
/// // Instantiate a VM.
/// let mut bpf_functions = std::collections::BTreeMap::new();
/// register_bpf_function(&mut bpf_functions, 0, "entrypoint").unwrap();
/// let mut executable = Executable::<UserError, DefaultInstructionMeter>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut executable = <dyn Executable::<UserError, DefaultInstructionMeter>>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut vm = EbpfVm::<UserError, DefaultInstructionMeter>::new(executable.as_ref(), mem, &[]).unwrap();
///
/// // Provide a reference to the packet data.
Expand Down Expand Up @@ -457,7 +457,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EbpfVm<'a, E, I> {
/// // Instantiate a VM.
/// let mut bpf_functions = std::collections::BTreeMap::new();
/// register_bpf_function(&mut bpf_functions, 0, "entrypoint").unwrap();
/// let mut executable = Executable::<UserError, DefaultInstructionMeter>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut executable = <dyn Executable::<UserError, DefaultInstructionMeter>>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut vm = EbpfVm::<UserError, DefaultInstructionMeter>::new(executable.as_ref(), &mut [], &[]).unwrap();
/// ```
pub fn new(
Expand Down Expand Up @@ -565,7 +565,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EbpfVm<'a, E, I> {
/// // Instantiate an Executable and VM
/// let mut bpf_functions = std::collections::BTreeMap::new();
/// register_bpf_function(&mut bpf_functions, 0, "entrypoint").unwrap();
/// let mut executable = Executable::<UserError, DefaultInstructionMeter>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut executable = <dyn Executable::<UserError, DefaultInstructionMeter>>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// executable.set_syscall_registry(syscall_registry);
/// let mut vm = EbpfVm::<UserError, DefaultInstructionMeter>::new(executable.as_ref(), &mut [], &[]).unwrap();
/// // Bind a context object instance to the previously registered syscall
Expand Down Expand Up @@ -630,7 +630,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EbpfVm<'a, E, I> {
/// // Instantiate a VM.
/// let mut bpf_functions = std::collections::BTreeMap::new();
/// register_bpf_function(&mut bpf_functions, 0, "entrypoint").unwrap();
/// let mut executable = Executable::<UserError, DefaultInstructionMeter>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut executable = <dyn Executable::<UserError, DefaultInstructionMeter>>::from_text_bytes(prog, bpf_functions, None, Config::default()).unwrap();
/// let mut vm = EbpfVm::<UserError, DefaultInstructionMeter>::new(executable.as_ref(), mem, &[]).unwrap();
///
/// // Provide a reference to the packet data.
Expand Down

0 comments on commit 6f0effe

Please sign in to comment.