From 7f4d6d376fa2c28021ac5a60bc65a0315e0b1228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 28 Sep 2023 21:14:20 +0200 Subject: [PATCH 1/3] Stops allocating errors on the heap. --- src/debugger.rs | 3 +- src/error.rs | 8 +++- src/interpreter.rs | 2 +- src/jit.rs | 50 ++++++++------------ src/memory_region.rs | 20 ++++---- src/vm.rs | 8 ++-- tests/execution.rs | 109 ++++++++++++++++++++----------------------- 7 files changed, 93 insertions(+), 107 deletions(-) diff --git a/src/debugger.rs b/src/debugger.rs index 8fa0f33e..be35061a 100644 --- a/src/debugger.rs +++ b/src/debugger.rs @@ -23,6 +23,7 @@ use gdbstub::target::ext::section_offsets::Offsets; use crate::{ ebpf, + error::EbpfError, interpreter::{DebugState, Interpreter}, memory_region::AccessType, vm::{ContextObject, ProgramResult}, @@ -152,7 +153,7 @@ fn get_host_ptr( interpreter: &mut Interpreter, mut vm_addr: u64, pc: usize, -) -> Result<*mut u8, Box> { +) -> Result<*mut u8, EbpfError> { if vm_addr < ebpf::MM_PROGRAM_START { vm_addr += ebpf::MM_PROGRAM_START; } diff --git a/src/error.rs b/src/error.rs index 6e4c3b35..49ad5f4f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,7 +17,10 @@ //! , or for a shorter version of //! the list of the operation codes: -use crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError}; +use { + crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError}, + std::error::Error, +}; /// Error definitions #[derive(Debug, thiserror::Error)] @@ -86,4 +89,7 @@ pub enum EbpfError { /// Verifier error #[error("Verifier error: {0}")] VerifierError(#[from] VerifierError), + /// Syscall error + #[error("Syscall error: {0}")] + SyscallError(Box), } diff --git a/src/interpreter.rs b/src/interpreter.rs index 8f5ae856..ae0b90ea 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -49,7 +49,7 @@ macro_rules! translate_memory_access { macro_rules! throw_error { ($self:expr, $err:expr) => {{ - $self.vm.program_result = ProgramResult::Err(Box::new($err)); + $self.vm.program_result = ProgramResult::Err($err); return false; }}; (DivideByZero; $self:expr, $pc:expr, $src:expr, $ty:ty) => { diff --git a/src/jit.rs b/src/jit.rs index 21bb3894..c03265f6 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -183,21 +183,20 @@ impl PartialEq for JitProgram { const ANCHOR_TRACE: usize = 0; const ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS: usize = 1; const ANCHOR_EPILOGUE: usize = 2; -const ANCHOR_ALLOCATE_EXCEPTION: usize = 3; -const ANCHOR_THROW_EXCEPTION_UNCHECKED: usize = 4; -const ANCHOR_EXIT: usize = 5; -const ANCHOR_THROW_EXCEPTION: usize = 6; -const ANCHOR_ACCESS_VIOLATION: usize = 7; -const ANCHOR_CALL_DEPTH_EXCEEDED: usize = 8; -const ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT: usize = 9; -const ANCHOR_DIV_BY_ZERO: usize = 10; -const ANCHOR_DIV_OVERFLOW: usize = 11; -const ANCHOR_CALL_UNSUPPORTED_INSTRUCTION: usize = 12; -const ANCHOR_EXTERNAL_FUNCTION_CALL: usize = 13; -const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE: usize = 14; -const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_REG: usize = 15; -const ANCHOR_TRANSLATE_MEMORY_ADDRESS: usize = 23; -const ANCHOR_COUNT: usize = 32; // Update me when adding or removing anchors +const ANCHOR_THROW_EXCEPTION_UNCHECKED: usize = 3; +const ANCHOR_EXIT: usize = 4; +const ANCHOR_THROW_EXCEPTION: usize = 5; +const ANCHOR_ACCESS_VIOLATION: usize = 6; +const ANCHOR_CALL_DEPTH_EXCEEDED: usize = 7; +const ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT: usize = 8; +const ANCHOR_DIV_BY_ZERO: usize = 9; +const ANCHOR_DIV_OVERFLOW: usize = 10; +const ANCHOR_CALL_UNSUPPORTED_INSTRUCTION: usize = 11; +const ANCHOR_EXTERNAL_FUNCTION_CALL: usize = 12; +const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE: usize = 13; +const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_REG: usize = 14; +const ANCHOR_TRANSLATE_MEMORY_ADDRESS: usize = 22; +const ANCHOR_COUNT: usize = 31; // Update me when adding or removing anchors const REGISTER_MAP: [u8; 11] = [ CALLER_SAVED_REGISTERS[0], @@ -257,7 +256,7 @@ enum RuntimeEnvironmentSlot { StopwatchNumerator = 5, StopwatchDenominator = 6, ProgramResult = 7, - MemoryMapping = 10, + MemoryMapping = 15, } /* Explaination of the Instruction Meter @@ -1285,8 +1284,10 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { } fn emit_set_exception_kind(&mut self, err: EbpfError) { - self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_ALLOCATE_EXCEPTION, 5))); let err_kind = unsafe { *(&err as *const _ as *const u64) }; + let err_discriminant = ProgramResult::Err(err).discriminant(); + self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32)))); + self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(-(std::mem::size_of::() as i32)), err_discriminant as i64)); // result.discriminant = err_discriminant; self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(0), err_kind as i64)); // err.kind = err_kind; } @@ -1340,20 +1341,6 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_ins(X86Instruction::load(OperandSize::S64, RBP, RSP, X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::HostStackPointer)))); self.emit_ins(X86Instruction::return_near()); - // Routine for allocating errors - self.set_anchor(ANCHOR_ALLOCATE_EXCEPTION); - unsafe fn allocate_error(result: *mut ProgramResult) -> *mut EbpfError { - let err_ptr = std::alloc::alloc(std::alloc::Layout::new::()) as *mut EbpfError; - assert!(!err_ptr.is_null(), "std::alloc::alloc() failed"); - result.write(ProgramResult::Err(Box::from_raw(err_ptr))); - err_ptr - } - self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult))))); - self.emit_rust_call(Value::Constant64(allocate_error as usize as i64, false), &[ - Argument { index: 0, value: Value::Register(R10) }, - ], Some(R10)); - self.emit_ins(X86Instruction::return_near()); - // Handler for EbpfError::ExceededMaxInstructions self.set_anchor(ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS); self.emit_set_exception_kind(EbpfError::ExceededMaxInstructions(0)); @@ -1362,6 +1349,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { // Epilogue for errors self.set_anchor(ANCHOR_THROW_EXCEPTION_UNCHECKED); + self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32)))); self.emit_ins(X86Instruction::store(OperandSize::S64, R11, R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32))); // result.pc = self.pc; self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x81, 0, R10, ebpf::ELF_INSN_DUMP_OFFSET as i64, Some(X86IndirectAccess::Offset(std::mem::size_of::() as i32)))); // result.pc += ebpf::ELF_INSN_DUMP_OFFSET; self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_EPILOGUE, 5))); diff --git a/src/memory_region.rs b/src/memory_region.rs index 17c311de..367d614d 100644 --- a/src/memory_region.rs +++ b/src/memory_region.rs @@ -135,7 +135,7 @@ impl MemoryRegion { // address, eg with rodata regions if config.optimize_rodata = true, see // Elf::get_ro_region. if vm_addr < self.vm_addr { - return ProgramResult::Err(Box::new(EbpfError::InvalidVirtualAddress(vm_addr))); + return ProgramResult::Err(EbpfError::InvalidVirtualAddress(vm_addr)); } let begin_offset = vm_addr.saturating_sub(self.vm_addr); @@ -152,7 +152,7 @@ impl MemoryRegion { return ProgramResult::Ok(self.host_addr.get().saturating_add(gapped_offset)); } } - ProgramResult::Err(Box::new(EbpfError::InvalidVirtualAddress(vm_addr))) + ProgramResult::Err(EbpfError::InvalidVirtualAddress(vm_addr)) } } @@ -533,7 +533,7 @@ impl<'a> UnalignedMemoryMapping<'a> { &self, access_type: AccessType, vm_addr: u64, - ) -> Result<&MemoryRegion, Box> { + ) -> Result<&MemoryRegion, EbpfError> { // Safety: // &mut references to the mapping cache are only created internally from methods that do not // invoke each other. UnalignedMemoryMapping is !Sync, so the cache reference below is @@ -710,7 +710,7 @@ impl<'a> AlignedMemoryMapping<'a> { &self, access_type: AccessType, vm_addr: u64, - ) -> Result<&MemoryRegion, Box> { + ) -> Result<&MemoryRegion, EbpfError> { let index = vm_addr .checked_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32) .unwrap_or(0) as usize; @@ -850,9 +850,9 @@ impl<'a> MemoryMapping<'a> { &self, access_type: AccessType, vm_addr: u64, - ) -> Result<&MemoryRegion, Box> { + ) -> Result<&MemoryRegion, EbpfError> { match self { - MemoryMapping::Identity => Err(Box::new(EbpfError::InvalidMemoryRegion(0))), + MemoryMapping::Identity => Err(EbpfError::InvalidMemoryRegion(0)), MemoryMapping::Aligned(m) => m.region(access_type, vm_addr), MemoryMapping::Unaligned(m) => m.region(access_type, vm_addr), } @@ -911,13 +911,13 @@ fn generate_access_violation( if !sbpf_version.dynamic_stack_frames() && (-1..(config.max_call_depth as i64).saturating_add(1)).contains(&stack_frame) { - ProgramResult::Err(Box::new(EbpfError::StackAccessViolation( + ProgramResult::Err(EbpfError::StackAccessViolation( pc, access_type, vm_addr, len, stack_frame, - ))) + )) } else { let region_name = match vm_addr & (!ebpf::MM_PROGRAM_START.saturating_sub(1)) { ebpf::MM_PROGRAM_START => "program", @@ -926,13 +926,13 @@ fn generate_access_violation( ebpf::MM_INPUT_START => "input", _ => "unknown", }; - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( pc, access_type, vm_addr, len, region_name, - ))) + )) } } diff --git a/src/vm.rs b/src/vm.rs index 381e66ff..89174bb4 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -98,7 +98,7 @@ impl From> for StableResult { } /// Return value of programs and syscalls -pub type ProgramResult = StableResult>; +pub type ProgramResult = StableResult; /// VM configuration settings #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -457,7 +457,7 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { { let compiled_program = match executable .get_compiled_program() - .ok_or_else(|| Box::new(EbpfError::JitNotCompiled)) + .ok_or_else(|| EbpfError::JitNotCompiled) { Ok(compiled_program) => compiled_program, Err(error) => return (0, ProgramResult::Err(error)), @@ -470,7 +470,7 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { } #[cfg(not(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64")))] { - return (0, ProgramResult::Err(Box::new(EbpfError::JitNotCompiled))); + return (0, ProgramResult::Err(EbpfError::JitNotCompiled)); } }; let instruction_count = if config.enable_instruction_meter { @@ -494,7 +494,7 @@ mod tests { fn test_program_result_is_stable() { let ok = ProgramResult::Ok(42); assert_eq!(ok.discriminant(), 0); - let err = ProgramResult::Err(Box::new(EbpfError::JitNotCompiled)); + let err = ProgramResult::Err(EbpfError::JitNotCompiled); assert_eq!(err.discriminant(), 1); } diff --git a/tests/execution.rs b/tests/execution.rs index bb9ff267..d65f61b4 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -744,7 +744,7 @@ fn test_err_divide_by_zero() { executable, [], TestContextObject::new(2), - ProgramResult::Err(Box::new(EbpfError::DivideByZero(30))), + ProgramResult::Err(EbpfError::DivideByZero(30)), ); } } @@ -786,7 +786,7 @@ fn test_err_divide_overflow() { executable, [], TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::DivideOverflow(32))), + ProgramResult::Err(EbpfError::DivideOverflow(32)), ); } } @@ -891,13 +891,13 @@ fn test_err_ldxdw_oob() { ], (), TestContextObject::new(1), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 29, AccessType::Load, 0x400000006, 8, "input" - ))), + )), ); } @@ -910,13 +910,13 @@ fn test_err_ldxdw_nomem() { [], (), TestContextObject::new(1), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 29, AccessType::Load, 0x400000006, 8, "input" - ))), + )), ); } @@ -1345,7 +1345,7 @@ fn test_exit_capped() { [], (), TestContextObject::new(0), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(29))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(29)), ); } @@ -1958,13 +1958,13 @@ fn test_err_dynamic_stack_out_of_bound() { [], (), TestContextObject::new(1), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 29, AccessType::Store, ebpf::MM_STACK_START - 1, 1, "program" - ))), + )), ); // Check that accessing MM_STACK_START + expected_stack_len fails @@ -1976,13 +1976,13 @@ fn test_err_dynamic_stack_out_of_bound() { [], (), TestContextObject::new(1), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 29, AccessType::Store, ebpf::MM_STACK_START + config.stack_size() as u64, 1, "stack" - ))), + )), ); } @@ -2010,13 +2010,13 @@ fn test_err_dynamic_stack_ptr_overflow() { [], (), TestContextObject::new(7), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 36, AccessType::Store, u64::MAX, 1, "unknown" - ))), + )), ); } @@ -2158,10 +2158,7 @@ fn test_stack_call_depth_tracking() { [], (), TestContextObject::new(2), - ProgramResult::Err(Box::new(EbpfError::CallDepthExceeded( - 31, - config.max_call_depth - ))), + ProgramResult::Err(EbpfError::CallDepthExceeded(31, config.max_call_depth)), ); } } @@ -2190,13 +2187,13 @@ fn test_err_mem_access_out_of_bound() { executable, mem, TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 31, AccessType::Store, address, 1, "unknown" - ))), + )), ); } } @@ -2295,7 +2292,7 @@ fn test_err_callx_unregistered() { [], (), TestContextObject::new(6), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(35))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(35)), ); } @@ -2309,7 +2306,7 @@ fn test_err_callx_oob_low() { [], (), TestContextObject::new(2), - ProgramResult::Err(Box::new(EbpfError::CallOutsideTextSegment(30, 0))), + ProgramResult::Err(EbpfError::CallOutsideTextSegment(30, 0)), ); } @@ -2325,10 +2322,7 @@ fn test_err_callx_oob_high() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::CallOutsideTextSegment( - 32, - 0xffffffff00000000 - ))), + ProgramResult::Err(EbpfError::CallOutsideTextSegment(32, 0xffffffff00000000)), ); } @@ -2365,10 +2359,10 @@ fn test_bpf_to_bpf_depth() { [Config::default().max_call_depth as u8 + 1], (), TestContextObject::new(60), - ProgramResult::Err(Box::new(EbpfError::CallDepthExceeded( + ProgramResult::Err(EbpfError::CallDepthExceeded( 35, Config::default().max_call_depth - ))), + )), ); } @@ -2384,10 +2378,7 @@ fn test_err_reg_stack_depth() { [], (), TestContextObject::new(60), - ProgramResult::Err(Box::new(EbpfError::CallDepthExceeded( - 31, - config.max_call_depth - ))), + ProgramResult::Err(EbpfError::CallDepthExceeded(31, config.max_call_depth)), ); } @@ -2431,7 +2422,7 @@ fn test_err_syscall_string() { "bpf_syscall_string" => syscalls::bpf_syscall_string, ), TestContextObject::new(2), - ProgramResult::Err(Box::new(EbpfError::AccessViolation(0, AccessType::Load, 0, 0, "unknown"))), + ProgramResult::Err(EbpfError::AccessViolation(0, AccessType::Load, 0, 0, "unknown")), ); } @@ -2529,7 +2520,7 @@ fn nested_vm_syscall( *result = if throw == 0 { ProgramResult::Ok(42) } else { - ProgramResult::Err(Box::new(EbpfError::CallDepthExceeded(33, 0))) + ProgramResult::Err(EbpfError::CallDepthExceeded(33, 0)) }; #[allow(unused_mut)] if depth > 0 { @@ -2600,7 +2591,7 @@ fn test_tight_infinite_loop_conditional() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(30))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(30)), ); } @@ -2613,7 +2604,7 @@ fn test_tight_infinite_loop_unconditional() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(30))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(30)), ); } @@ -2628,7 +2619,7 @@ fn test_tight_infinite_recursion() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(31))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(31)), ); } @@ -2648,7 +2639,7 @@ fn test_tight_infinite_recursion_callx() { [], (), TestContextObject::new(8), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(36))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), ); } @@ -2682,7 +2673,7 @@ fn test_err_instruction_count_syscall_capped() { "bpf_syscall_string" => syscalls::bpf_syscall_string, ), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(32))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(32)), ); } @@ -2703,7 +2694,7 @@ fn test_non_terminate_early() { [], (), TestContextObject::new(7), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(35))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(35)), ); } @@ -2726,7 +2717,7 @@ fn test_err_non_terminate_capped() { "bpf_trace_printf" => syscalls::bpf_trace_printf, ), TestContextObject::new(7), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(36))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), ); test_interpreter_and_jit_asm!( " @@ -2745,7 +2736,7 @@ fn test_err_non_terminate_capped() { "bpf_trace_printf" => syscalls::bpf_trace_printf, ), TestContextObject::new(1000), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(37))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(37)), ); } @@ -2763,7 +2754,7 @@ fn test_err_capped_before_exception() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(33))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), ); test_interpreter_and_jit_asm!( " @@ -2777,7 +2768,7 @@ fn test_err_capped_before_exception() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(33))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), ); } @@ -2796,7 +2787,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(5), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(35))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(35)), ); test_interpreter_and_jit_asm!( " @@ -2812,7 +2803,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(6), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(36))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), ); test_interpreter_and_jit_asm!( " @@ -2824,7 +2815,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(33))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), ); } @@ -2864,7 +2855,7 @@ fn test_err_call_unresolved() { [], (), TestContextObject::new(6), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(34))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(34)), ); } @@ -2919,7 +2910,7 @@ fn test_err_unresolved_syscall_static() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(32))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(32)), ); } @@ -3425,13 +3416,13 @@ fn test_err_fixed_stack_out_of_bound() { [], (), TestContextObject::new(1), - ProgramResult::Err(Box::new(EbpfError::AccessViolation( + ProgramResult::Err(EbpfError::AccessViolation( 29, AccessType::Store, 0x1FFFFD000, 1, "program" - ))), + )), ); } @@ -3492,7 +3483,7 @@ fn test_lddw() { [], (), TestContextObject::new(4), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(33))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), ); test_interpreter_and_jit_asm!( " @@ -3506,7 +3497,7 @@ fn test_lddw() { [], (), TestContextObject::new(5), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(34))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(34)), ); test_interpreter_and_jit_asm!( " @@ -3523,7 +3514,7 @@ fn test_lddw() { [], (), TestContextObject::new(5), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(36))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(36)), ); test_interpreter_and_jit_asm!( " @@ -3539,7 +3530,7 @@ fn test_lddw() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::UnsupportedInstruction(36))), + ProgramResult::Err(EbpfError::UnsupportedInstruction(36)), ); test_interpreter_and_jit_asm!( " @@ -3552,7 +3543,7 @@ fn test_lddw() { [], (), TestContextObject::new(2), - ProgramResult::Err(Box::new(EbpfError::ExceededMaxInstructions(32))), + ProgramResult::Err(EbpfError::ExceededMaxInstructions(32)), ); } @@ -3849,7 +3840,7 @@ fn test_div() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::DivideByZero(31))), + ProgramResult::Err(EbpfError::DivideByZero(31)), ); test_interpreter_and_jit_asm!( " @@ -3861,7 +3852,7 @@ fn test_div() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::DivideByZero(31))), + ProgramResult::Err(EbpfError::DivideByZero(31)), ); } @@ -3922,7 +3913,7 @@ fn test_mod() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::DivideByZero(31))), + ProgramResult::Err(EbpfError::DivideByZero(31)), ); test_interpreter_and_jit_asm!( " @@ -3934,6 +3925,6 @@ fn test_mod() { [], (), TestContextObject::new(3), - ProgramResult::Err(Box::new(EbpfError::DivideByZero(31))), + ProgramResult::Err(EbpfError::DivideByZero(31)), ); } From 765ec489b979a872fc7940cce9f86d8d4a880557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 28 Sep 2023 22:13:50 +0200 Subject: [PATCH 2/3] Removes all fields from runtime errors, leaving only the discriminant. --- src/error.rs | 34 +++++++-------- src/interpreter.rs | 101 ++++++++++++++++++--------------------------- src/jit.rs | 33 +++++++-------- tests/execution.rs | 74 ++++++++++++++++----------------- 4 files changed, 105 insertions(+), 137 deletions(-) diff --git a/src/error.rs b/src/error.rs index 49ad5f4f..513ee941 100644 --- a/src/error.rs +++ b/src/error.rs @@ -33,28 +33,26 @@ pub enum EbpfError { #[error("function #{0} was already registered")] FunctionAlreadyRegistered(usize), /// Exceeded max BPF to BPF call depth - #[error("exceeded max BPF to BPF call depth of {1} at BPF instruction #{0}")] - CallDepthExceeded(usize, usize), + #[error("exceeded max BPF to BPF call depth")] + CallDepthExceeded, /// Attempt to exit from root call frame #[error("attempted to exit root call frame")] ExitRootCallFrame, /// Divide by zero" - #[error("divide by zero at BPF instruction {0}")] - DivideByZero(usize), + #[error("divide by zero at BPF instruction")] + DivideByZero, /// Divide overflow - #[error("division overflow at BPF instruction {0}")] - DivideOverflow(usize), + #[error("division overflow at BPF instruction")] + DivideOverflow, /// Exceeded max instructions allowed - #[error("attempted to execute past the end of the text segment at BPF instruction #{0}")] - ExecutionOverrun(usize), + #[error("attempted to execute past the end of the text segment at BPF instruction")] + ExecutionOverrun, /// Attempt to call to an address outside the text segment - #[error( - "callx at BPF instruction {0} attempted to call outside of the text segment to addr 0x{1:x}" - )] - CallOutsideTextSegment(usize, u64), + #[error("callx attempted to call outside of the text segment")] + CallOutsideTextSegment, /// Exceeded max instructions allowed - #[error("exceeded CUs meter at BPF instruction #{0}")] - ExceededMaxInstructions(usize), + #[error("exceeded CUs meter at BPF instruction")] + ExceededMaxInstructions, /// Program has not been JIT-compiled #[error("program has not been JIT-compiled")] JitNotCompiled, @@ -75,11 +73,11 @@ pub enum EbpfError { )] StackAccessViolation(usize, AccessType, u64, u64, i64), /// Invalid instruction - #[error("invalid BPF instruction at {0}")] - InvalidInstruction(usize), + #[error("invalid BPF instruction")] + InvalidInstruction, /// Unsupported instruction - #[error("unsupported BPF instruction at {0}")] - UnsupportedInstruction(usize), + #[error("unsupported BPF instruction")] + UnsupportedInstruction, /// Compilation is too big to fit #[error("Compilation exhausted text segment at BPF instruction {0}")] ExhaustedTextSegment(usize), diff --git a/src/interpreter.rs b/src/interpreter.rs index ae0b90ea..cb067978 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -52,20 +52,14 @@ macro_rules! throw_error { $self.vm.program_result = ProgramResult::Err($err); return false; }}; - (DivideByZero; $self:expr, $pc:expr, $src:expr, $ty:ty) => { + (DivideByZero; $self:expr, $src:expr, $ty:ty) => { if $src as $ty == 0 { - throw_error!( - $self, - EbpfError::DivideByZero($pc + ebpf::ELF_INSN_DUMP_OFFSET) - ); + throw_error!($self, EbpfError::DivideByZero); } }; - (DivideOverflow; $self:expr, $pc:expr, $src:expr, $dst:expr, $ty:ty) => { + (DivideOverflow; $self:expr, $src:expr, $dst:expr, $ty:ty) => { if $dst as $ty == <$ty>::MIN && $src as $ty == -1 { - throw_error!( - $self, - EbpfError::DivideOverflow($pc + ebpf::ELF_INSN_DUMP_OFFSET) - ); + throw_error!($self, EbpfError::DivideOverflow); } }; } @@ -121,7 +115,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { } } - fn check_pc(&mut self, current_pc: usize) -> bool { + fn check_pc(&mut self) -> bool { if self .pc .checked_mul(ebpf::INSN_SIZE) @@ -130,13 +124,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { { true } else { - throw_error!( - self, - EbpfError::CallOutsideTextSegment( - current_pc + ebpf::ELF_INSN_DUMP_OFFSET, - self.program_vm_addr + (self.pc * ebpf::INSN_SIZE) as u64, - ) - ); + throw_error!(self, EbpfError::CallOutsideTextSegment); } } @@ -156,13 +144,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { self.vm.call_depth += 1; if self.vm.call_depth as usize == config.max_call_depth { - throw_error!( - self, - EbpfError::CallDepthExceeded( - self.pc + ebpf::ELF_INSN_DUMP_OFFSET - 1, - config.max_call_depth, - ) - ); + throw_error!(self, EbpfError::CallDepthExceeded); } if !self.executable.get_sbpf_version().dynamic_stack_frames() { @@ -183,12 +165,11 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { pub fn step(&mut self) -> bool { let config = &self.executable.get_config(); - let mut instruction_width = 1; self.due_insn_count += 1; let pc = self.pc; - self.pc += instruction_width; + self.pc += 1; if self.pc * ebpf::INSN_SIZE > self.program.len() { - throw_error!(self, EbpfError::ExecutionOverrun(pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::ExecutionOverrun); } let mut insn = ebpf::get_insn_unchecked(self.program, pc); let dst = insn.dst as usize; @@ -214,7 +195,6 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::LD_DW_IMM => { ebpf::augment_lddw_unchecked(self.program, &mut insn); - instruction_width = 2; self.pc += 1; self.reg[dst] = insn.imm as u64; }, @@ -286,7 +266,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::MUL32_REG if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as i32).wrapping_mul(self.reg[src] as i32) as u64, ebpf::DIV32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32 / insn.imm as u32) as u64, ebpf::DIV32_REG if !self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u32); + throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 / self.reg[src] as u32) as u64; }, ebpf::OR32_IMM => self.reg[dst] = (self.reg[dst] as u32 | insn.imm as u32) as u64, @@ -300,7 +280,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::NEG32 if self.executable.get_sbpf_version().enable_neg() => self.reg[dst] = (self.reg[dst] as i32).wrapping_neg() as u64 & (u32::MAX as u64), ebpf::MOD32_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = (self.reg[dst] as u32 % insn.imm as u32) as u64, ebpf::MOD32_REG if !self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u32); + throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 % self.reg[src] as u32) as u64; }, ebpf::XOR32_IMM => self.reg[dst] = (self.reg[dst] as u32 ^ insn.imm as u32) as u64, @@ -315,7 +295,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { 32 => (self.reg[dst] as u32).to_le() as u64, 64 => self.reg[dst].to_le(), _ => { - throw_error!(self, EbpfError::InvalidInstruction(pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::InvalidInstruction); } }; }, @@ -325,7 +305,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { 32 => (self.reg[dst] as u32).to_be() as u64, 64 => self.reg[dst].to_be(), _ => { - throw_error!(self, EbpfError::InvalidInstruction(pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::InvalidInstruction); } }; }, @@ -343,7 +323,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::MUL64_REG if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] = self.reg[dst].wrapping_mul(self.reg[src]), ebpf::DIV64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] /= insn.imm as u64, ebpf::DIV64_REG if !self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u64); + throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] /= self.reg[src]; }, ebpf::OR64_IMM => self.reg[dst] |= insn.imm as u64, @@ -357,7 +337,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::NEG64 if self.executable.get_sbpf_version().enable_neg() => self.reg[dst] = (self.reg[dst] as i64).wrapping_neg() as u64, ebpf::MOD64_IMM if !self.executable.get_sbpf_version().enable_pqr() => self.reg[dst] %= insn.imm as u64, ebpf::MOD64_REG if !self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u64); + throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] %= self.reg[src]; }, ebpf::XOR64_IMM => self.reg[dst] ^= insn.imm as u64, @@ -383,64 +363,64 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { self.reg[dst] = (self.reg[dst] as u32 / insn.imm as u32) as u64; } ebpf::UDIV32_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u32); + throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 / self.reg[src] as u32) as u64; }, ebpf::UDIV64_IMM if self.executable.get_sbpf_version().enable_pqr() => { self.reg[dst] /= insn.imm as u64; } ebpf::UDIV64_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u64); + throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] /= self.reg[src]; }, ebpf::UREM32_IMM if self.executable.get_sbpf_version().enable_pqr() => { self.reg[dst] = (self.reg[dst] as u32 % insn.imm as u32) as u64; } ebpf::UREM32_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u32); + throw_error!(DivideByZero; self, self.reg[src], u32); self.reg[dst] = (self.reg[dst] as u32 % self.reg[src] as u32) as u64; }, ebpf::UREM64_IMM if self.executable.get_sbpf_version().enable_pqr() => { self.reg[dst] %= insn.imm as u64; } ebpf::UREM64_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], u64); + throw_error!(DivideByZero; self, self.reg[src], u64); self.reg[dst] %= self.reg[src]; }, ebpf::SDIV32_IMM if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideOverflow; self, pc, insn.imm, self.reg[dst], i32); + throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i32); self.reg[dst] = (self.reg[dst] as i32 / insn.imm as i32) as u64; } ebpf::SDIV32_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], i32); - throw_error!(DivideOverflow; self, pc, self.reg[src], self.reg[dst], i32); + throw_error!(DivideByZero; self, self.reg[src], i32); + throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i32); self.reg[dst] = (self.reg[dst] as i32 / self.reg[src] as i32) as u64; }, ebpf::SDIV64_IMM if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideOverflow; self, pc, insn.imm, self.reg[dst], i64); + throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i64); self.reg[dst] = (self.reg[dst] as i64 / insn.imm) as u64; } ebpf::SDIV64_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], i64); - throw_error!(DivideOverflow; self, pc, self.reg[src], self.reg[dst], i64); + throw_error!(DivideByZero; self, self.reg[src], i64); + throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i64); self.reg[dst] = (self.reg[dst] as i64 / self.reg[src] as i64) as u64; }, ebpf::SREM32_IMM if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideOverflow; self, pc, insn.imm, self.reg[dst], i32); + throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i32); self.reg[dst] = (self.reg[dst] as i32 % insn.imm as i32) as u64; } ebpf::SREM32_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], i32); - throw_error!(DivideOverflow; self, pc, self.reg[src], self.reg[dst], i32); + throw_error!(DivideByZero; self, self.reg[src], i32); + throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i32); self.reg[dst] = (self.reg[dst] as i32 % self.reg[src] as i32) as u64; }, ebpf::SREM64_IMM if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideOverflow; self, pc, insn.imm, self.reg[dst], i64); + throw_error!(DivideOverflow; self, insn.imm, self.reg[dst], i64); self.reg[dst] = (self.reg[dst] as i64 % insn.imm) as u64; } ebpf::SREM64_REG if self.executable.get_sbpf_version().enable_pqr() => { - throw_error!(DivideByZero; self, pc, self.reg[src], i64); - throw_error!(DivideOverflow; self, pc, self.reg[src], self.reg[dst], i64); + throw_error!(DivideByZero; self, self.reg[src], i64); + throw_error!(DivideOverflow; self, self.reg[src], self.reg[dst], i64); self.reg[dst] = (self.reg[dst] as i64 % self.reg[src] as i64) as u64; }, @@ -479,15 +459,15 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { return false; } if target_pc < self.program_vm_addr { - throw_error!(self, EbpfError::CallOutsideTextSegment(pc + ebpf::ELF_INSN_DUMP_OFFSET, target_pc / ebpf::INSN_SIZE as u64 * ebpf::INSN_SIZE as u64)); + throw_error!(self, EbpfError::CallOutsideTextSegment); } self.pc = (target_pc - self.program_vm_addr) as usize / ebpf::INSN_SIZE; - if !self.check_pc(pc) { + if !self.check_pc() { return false; } if self.executable.get_sbpf_version().static_syscalls() && self.executable.get_function_registry().lookup_by_key(self.pc as u32).is_none() { self.due_insn_count += 1; - throw_error!(self, EbpfError::UnsupportedInstruction(self.pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::UnsupportedInstruction); } }, @@ -538,21 +518,21 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { return false; } self.pc = target_pc; - if !self.check_pc(pc) { + if !self.check_pc() { return false; } } } if !resolved { - throw_error!(self, EbpfError::UnsupportedInstruction(pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::UnsupportedInstruction); } } ebpf::EXIT => { if self.vm.call_depth == 0 { if config.enable_instruction_meter && self.due_insn_count > self.vm.previous_instruction_meter { - throw_error!(self, EbpfError::ExceededMaxInstructions(pc + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::ExceededMaxInstructions); } self.vm.program_result = ProgramResult::Ok(self.reg[0]); return false; @@ -570,16 +550,15 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { config.stack_frame_size * if config.enable_stack_frame_gaps { 2 } else { 1 }; self.vm.stack_pointer -= stack_frame_size as u64; } - if !self.check_pc(pc) { + if !self.check_pc() { return false; } } - _ => throw_error!(self, EbpfError::UnsupportedInstruction(pc + ebpf::ELF_INSN_DUMP_OFFSET)), + _ => throw_error!(self, EbpfError::UnsupportedInstruction), } if config.enable_instruction_meter && self.due_insn_count >= self.vm.previous_instruction_meter { - // Use `pc + instruction_width` instead of `self.pc` here because jumps and calls don't continue at the end of this instruction - throw_error!(self, EbpfError::ExceededMaxInstructions(pc + instruction_width + ebpf::ELF_INSN_DUMP_OFFSET)); + throw_error!(self, EbpfError::ExceededMaxInstructions); } true diff --git a/src/jit.rs b/src/jit.rs index c03265f6..36eb809e 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -528,7 +528,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { } 64 => {} _ => { - return Err(EbpfError::InvalidInstruction(self.pc + ebpf::ELF_INSN_DUMP_OFFSET)); + return Err(EbpfError::InvalidInstruction); } } }, @@ -541,7 +541,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { 32 => self.emit_ins(X86Instruction::bswap(OperandSize::S32, dst)), 64 => self.emit_ins(X86Instruction::bswap(OperandSize::S64, dst)), _ => { - return Err(EbpfError::InvalidInstruction(self.pc + ebpf::ELF_INSN_DUMP_OFFSET)); + return Err(EbpfError::InvalidInstruction); } } }, @@ -711,7 +711,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_ins(X86Instruction::return_near()); }, - _ => return Err(EbpfError::UnsupportedInstruction(self.pc + ebpf::ELF_INSN_DUMP_OFFSET)), + _ => return Err(EbpfError::UnsupportedInstruction), } self.pc += 1; @@ -722,8 +722,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { return Err(EbpfError::ExhaustedTextSegment(self.pc)); } self.emit_validate_and_profile_instruction_count(true, Some(self.pc + 2)); - self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, R11, self.pc as i64)); - self.emit_set_exception_kind(EbpfError::ExecutionOverrun(0)); + self.emit_set_exception_kind(EbpfError::ExecutionOverrun); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); self.resolve_jumps(); @@ -1232,7 +1231,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_ins(X86Instruction::test(size, R11, R11, None)); // r11 == 0 } - // MIN / -1, raise EbpfError::DivideOverflow(pc) + // MIN / -1, raise EbpfError::DivideOverflow self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, R11, self.pc as i64)); self.emit_ins(X86Instruction::conditional_jump_immediate(0x84, self.relative_to_anchor(ANCHOR_DIV_OVERFLOW, 6))); } @@ -1343,15 +1342,12 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { // Handler for EbpfError::ExceededMaxInstructions self.set_anchor(ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS); - self.emit_set_exception_kind(EbpfError::ExceededMaxInstructions(0)); + self.emit_set_exception_kind(EbpfError::ExceededMaxInstructions); self.emit_ins(X86Instruction::mov(OperandSize::S64, ARGUMENT_REGISTERS[0], R11)); // R11 = instruction_meter; // Fall through // Epilogue for errors self.set_anchor(ANCHOR_THROW_EXCEPTION_UNCHECKED); - self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32)))); - self.emit_ins(X86Instruction::store(OperandSize::S64, R11, R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32))); // result.pc = self.pc; - self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x81, 0, R10, ebpf::ELF_INSN_DUMP_OFFSET as i64, Some(X86IndirectAccess::Offset(std::mem::size_of::() as i32)))); // result.pc += ebpf::ELF_INSN_DUMP_OFFSET; self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_EPILOGUE, 5))); // Quit gracefully @@ -1370,29 +1366,28 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { // Handler for EbpfError::AccessViolation self.set_anchor(ANCHOR_ACCESS_VIOLATION); - self.emit_ins(X86Instruction::load(OperandSize::S64, RBP, R10, X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32))); // err = *env.result.err; + self.emit_ins(X86Instruction::store(OperandSize::S64, R11, R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32 * 2))); // result.pc = self.pc; + self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x81, 0, R10, ebpf::ELF_INSN_DUMP_OFFSET as i64, Some(X86IndirectAccess::Offset(std::mem::size_of::() as i32 * 2)))); // result.pc += ebpf::ELF_INSN_DUMP_OFFSET; self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Handler for EbpfError::CallDepthExceeded self.set_anchor(ANCHOR_CALL_DEPTH_EXCEEDED); - self.emit_set_exception_kind(EbpfError::CallDepthExceeded(0, 0)); - self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset((std::mem::size_of::() * 2) as i32), self.config.max_call_depth as i64)); // depth = jit.config.max_call_depth; + self.emit_set_exception_kind(EbpfError::CallDepthExceeded); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Handler for EbpfError::CallOutsideTextSegment self.set_anchor(ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT); - self.emit_set_exception_kind(EbpfError::CallOutsideTextSegment(0, 0)); - self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[0], R10, X86IndirectAccess::Offset((std::mem::size_of::() * 2) as i32))); // target_address = RAX; + self.emit_set_exception_kind(EbpfError::CallOutsideTextSegment); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Handler for EbpfError::DivideByZero self.set_anchor(ANCHOR_DIV_BY_ZERO); - self.emit_set_exception_kind(EbpfError::DivideByZero(0)); + self.emit_set_exception_kind(EbpfError::DivideByZero); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Handler for EbpfError::DivideOverflow self.set_anchor(ANCHOR_DIV_OVERFLOW); - self.emit_set_exception_kind(EbpfError::DivideOverflow(0)); + self.emit_set_exception_kind(EbpfError::DivideOverflow); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Handler for EbpfError::UnsupportedInstruction @@ -1400,7 +1395,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { if self.config.enable_instruction_tracing { self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_TRACE, 5))); } - self.emit_set_exception_kind(EbpfError::UnsupportedInstruction(0)); + self.emit_set_exception_kind(EbpfError::UnsupportedInstruction); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); // Routine for external functions @@ -1736,7 +1731,7 @@ mod tests { if result.is_err() { assert!(matches!( result.unwrap_err(), - EbpfError::UnsupportedInstruction(_) + EbpfError::UnsupportedInstruction )); continue; } diff --git a/tests/execution.rs b/tests/execution.rs index d65f61b4..06ddae37 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -744,7 +744,7 @@ fn test_err_divide_by_zero() { executable, [], TestContextObject::new(2), - ProgramResult::Err(EbpfError::DivideByZero(30)), + ProgramResult::Err(EbpfError::DivideByZero), ); } } @@ -786,7 +786,7 @@ fn test_err_divide_overflow() { executable, [], TestContextObject::new(4), - ProgramResult::Err(EbpfError::DivideOverflow(32)), + ProgramResult::Err(EbpfError::DivideOverflow), ); } } @@ -1345,7 +1345,7 @@ fn test_exit_capped() { [], (), TestContextObject::new(0), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(29)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2158,7 +2158,7 @@ fn test_stack_call_depth_tracking() { [], (), TestContextObject::new(2), - ProgramResult::Err(EbpfError::CallDepthExceeded(31, config.max_call_depth)), + ProgramResult::Err(EbpfError::CallDepthExceeded), ); } } @@ -2292,7 +2292,7 @@ fn test_err_callx_unregistered() { [], (), TestContextObject::new(6), - ProgramResult::Err(EbpfError::UnsupportedInstruction(35)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); } @@ -2306,7 +2306,7 @@ fn test_err_callx_oob_low() { [], (), TestContextObject::new(2), - ProgramResult::Err(EbpfError::CallOutsideTextSegment(30, 0)), + ProgramResult::Err(EbpfError::CallOutsideTextSegment), ); } @@ -2322,7 +2322,7 @@ fn test_err_callx_oob_high() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::CallOutsideTextSegment(32, 0xffffffff00000000)), + ProgramResult::Err(EbpfError::CallOutsideTextSegment), ); } @@ -2359,16 +2359,12 @@ fn test_bpf_to_bpf_depth() { [Config::default().max_call_depth as u8 + 1], (), TestContextObject::new(60), - ProgramResult::Err(EbpfError::CallDepthExceeded( - 35, - Config::default().max_call_depth - )), + ProgramResult::Err(EbpfError::CallDepthExceeded), ); } #[test] fn test_err_reg_stack_depth() { - let config = Config::default(); test_interpreter_and_jit_asm!( " mov64 r0, 0x1 @@ -2378,7 +2374,7 @@ fn test_err_reg_stack_depth() { [], (), TestContextObject::new(60), - ProgramResult::Err(EbpfError::CallDepthExceeded(31, config.max_call_depth)), + ProgramResult::Err(EbpfError::CallDepthExceeded), ); } @@ -2520,7 +2516,7 @@ fn nested_vm_syscall( *result = if throw == 0 { ProgramResult::Ok(42) } else { - ProgramResult::Err(EbpfError::CallDepthExceeded(33, 0)) + ProgramResult::Err(EbpfError::CallDepthExceeded) }; #[allow(unused_mut)] if depth > 0 { @@ -2577,7 +2573,7 @@ fn test_nested_vm_syscall() { &mut memory_mapping, &mut result, ); - assert_error!(result, "CallDepthExceeded(33, 0)"); + assert_error!(result, "CallDepthExceeded"); } // Instruction Meter Limit @@ -2591,7 +2587,7 @@ fn test_tight_infinite_loop_conditional() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(30)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2604,7 +2600,7 @@ fn test_tight_infinite_loop_unconditional() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(30)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2619,7 +2615,7 @@ fn test_tight_infinite_recursion() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(31)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2639,7 +2635,7 @@ fn test_tight_infinite_recursion_callx() { [], (), TestContextObject::new(8), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2673,7 +2669,7 @@ fn test_err_instruction_count_syscall_capped() { "bpf_syscall_string" => syscalls::bpf_syscall_string, ), TestContextObject::new(3), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(32)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2694,7 +2690,7 @@ fn test_non_terminate_early() { [], (), TestContextObject::new(7), - ProgramResult::Err(EbpfError::UnsupportedInstruction(35)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); } @@ -2717,7 +2713,7 @@ fn test_err_non_terminate_capped() { "bpf_trace_printf" => syscalls::bpf_trace_printf, ), TestContextObject::new(7), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); test_interpreter_and_jit_asm!( " @@ -2736,7 +2732,7 @@ fn test_err_non_terminate_capped() { "bpf_trace_printf" => syscalls::bpf_trace_printf, ), TestContextObject::new(1000), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(37)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2754,7 +2750,7 @@ fn test_err_capped_before_exception() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); test_interpreter_and_jit_asm!( " @@ -2768,7 +2764,7 @@ fn test_err_capped_before_exception() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2787,7 +2783,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(5), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(35)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); test_interpreter_and_jit_asm!( " @@ -2803,7 +2799,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(6), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(36)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); test_interpreter_and_jit_asm!( " @@ -2815,7 +2811,7 @@ fn test_err_exit_capped() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -2855,7 +2851,7 @@ fn test_err_call_unresolved() { [], (), TestContextObject::new(6), - ProgramResult::Err(EbpfError::UnsupportedInstruction(34)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); } @@ -2910,7 +2906,7 @@ fn test_err_unresolved_syscall_static() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::UnsupportedInstruction(32)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); } @@ -3483,7 +3479,7 @@ fn test_lddw() { [], (), TestContextObject::new(4), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(33)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); test_interpreter_and_jit_asm!( " @@ -3497,7 +3493,7 @@ fn test_lddw() { [], (), TestContextObject::new(5), - ProgramResult::Err(EbpfError::UnsupportedInstruction(34)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); test_interpreter_and_jit_asm!( " @@ -3514,7 +3510,7 @@ fn test_lddw() { [], (), TestContextObject::new(5), - ProgramResult::Err(EbpfError::UnsupportedInstruction(36)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); test_interpreter_and_jit_asm!( " @@ -3530,7 +3526,7 @@ fn test_lddw() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::UnsupportedInstruction(36)), + ProgramResult::Err(EbpfError::UnsupportedInstruction), ); test_interpreter_and_jit_asm!( " @@ -3543,7 +3539,7 @@ fn test_lddw() { [], (), TestContextObject::new(2), - ProgramResult::Err(EbpfError::ExceededMaxInstructions(32)), + ProgramResult::Err(EbpfError::ExceededMaxInstructions), ); } @@ -3840,7 +3836,7 @@ fn test_div() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::DivideByZero(31)), + ProgramResult::Err(EbpfError::DivideByZero), ); test_interpreter_and_jit_asm!( " @@ -3852,7 +3848,7 @@ fn test_div() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::DivideByZero(31)), + ProgramResult::Err(EbpfError::DivideByZero), ); } @@ -3913,7 +3909,7 @@ fn test_mod() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::DivideByZero(31)), + ProgramResult::Err(EbpfError::DivideByZero), ); test_interpreter_and_jit_asm!( " @@ -3925,6 +3921,6 @@ fn test_mod() { [], (), TestContextObject::new(3), - ProgramResult::Err(EbpfError::DivideByZero(31)), + ProgramResult::Err(EbpfError::DivideByZero), ); } From c9c5a3e66a8624d2d16a0b61bf2049030e0d5877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 29 Sep 2023 10:46:59 +0200 Subject: [PATCH 3/3] Also removes the pc field from EbpfError::AccessViolation. --- benches/memory_mapping.rs | 13 +-- src/debugger.rs | 4 +- src/error.rs | 12 +- src/interpreter.rs | 35 +++--- src/jit.rs | 50 ++++----- src/memory_region.rs | 228 +++++++++++++++----------------------- src/syscalls.rs | 14 +-- tests/execution.rs | 9 +- 8 files changed, 140 insertions(+), 225 deletions(-) diff --git a/benches/memory_mapping.rs b/benches/memory_mapping.rs index 799db71d..a6966db4 100644 --- a/benches/memory_mapping.rs +++ b/benches/memory_mapping.rs @@ -81,7 +81,6 @@ macro_rules! bench_gapped_randomized_access_with_1024_entries { AccessType::Load, 0x100000000 + (prng.gen::() % frame_count * (frame_size * 2)), 1, - 0, ) .is_ok()); }); @@ -119,7 +118,6 @@ macro_rules! bench_randomized_access_with_0001_entry { AccessType::Load, 0x100000000 + (prng.gen::() % content.len() as u64), 1, - 0, ); }); } @@ -153,7 +151,6 @@ macro_rules! bench_randomized_access_with_n_entries { AccessType::Load, 0x100000000 + (prng.gen::() % end_address), 1, - 0, ); }); } @@ -199,7 +196,7 @@ macro_rules! bench_randomized_mapping_with_n_entries { let config = Config::default(); let memory_mapping = $mem::new(memory_regions, &config, &SBPFVersion::V2).unwrap(); bencher.iter(|| { - let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1, 0); + let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1); }); } }; @@ -248,7 +245,7 @@ macro_rules! bench_mapping_with_n_entries { let config = Config::default(); let memory_mapping = $mem::new(memory_regions, &config, &SBPFVersion::V2).unwrap(); bencher.iter(|| { - let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1, 0); + let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1); }); } }; @@ -310,13 +307,13 @@ fn do_bench_mapping_operation(bencher: &mut Bencher, op: MemoryOperation, vm_add match op { MemoryOperation::Map => bencher.iter(|| { - let _ = memory_mapping.map(AccessType::Load, vm_addr, 8, 0).unwrap(); + let _ = memory_mapping.map(AccessType::Load, vm_addr, 8).unwrap(); }), MemoryOperation::Load => bencher.iter(|| { - let _ = memory_mapping.load::(vm_addr, 0).unwrap(); + let _ = memory_mapping.load::(vm_addr).unwrap(); }), MemoryOperation::Store(val) => bencher.iter(|| { - let _ = memory_mapping.store(val, vm_addr, 0).unwrap(); + let _ = memory_mapping.store(val, vm_addr).unwrap(); }), } } diff --git a/src/debugger.rs b/src/debugger.rs index be35061a..23f971ee 100644 --- a/src/debugger.rs +++ b/src/debugger.rs @@ -152,7 +152,6 @@ impl<'a, 'b, C: ContextObject> Target for Interpreter<'a, 'b, C> { fn get_host_ptr( interpreter: &mut Interpreter, mut vm_addr: u64, - pc: usize, ) -> Result<*mut u8, EbpfError> { if vm_addr < ebpf::MM_PROGRAM_START { vm_addr += ebpf::MM_PROGRAM_START; @@ -161,7 +160,6 @@ fn get_host_ptr( AccessType::Load, vm_addr, std::mem::size_of::() as u64, - pc + ebpf::ELF_INSN_DUMP_OFFSET, ) { ProgramResult::Ok(host_addr) => Ok(host_addr as *mut u8), ProgramResult::Err(err) => Err(err), @@ -197,7 +195,7 @@ impl<'a, 'b, C: ContextObject> SingleThreadBase for Interpreter<'a, 'b, C> { fn read_addrs(&mut self, start_addr: u64, data: &mut [u8]) -> TargetResult<(), Self> { for (vm_addr, val) in (start_addr..).zip(data.iter_mut()) { - let host_ptr = match get_host_ptr(self, vm_addr, self.pc) { + let host_ptr = match get_host_ptr(self, vm_addr) { Ok(host_ptr) => host_ptr, // The debugger is sometimes requesting more data than we have access to, just skip these _ => continue, diff --git a/src/error.rs b/src/error.rs index 513ee941..411db985 100644 --- a/src/error.rs +++ b/src/error.rs @@ -63,15 +63,11 @@ pub enum EbpfError { #[error("Invalid memory region at index {0}")] InvalidMemoryRegion(usize), /// Access violation (general) - #[error( - "Access violation in {4} section at address {2:#x} of size {3:?} at BPF instruction #{0}" - )] - AccessViolation(usize, AccessType, u64, u64, &'static str), + #[error("Access violation in {3} section at address {1:#x} of size {2:?}")] + AccessViolation(AccessType, u64, u64, &'static str), /// Access violation (stack specific) - #[error( - "Access violation in stack frame {4} at address {2:#x} of size {3:?} at BPF instruction #{0}" - )] - StackAccessViolation(usize, AccessType, u64, u64, i64), + #[error("Access violation in stack frame {3} at address {1:#x} of size {2:?}")] + StackAccessViolation(AccessType, u64, u64, i64), /// Invalid instruction #[error("invalid BPF instruction")] InvalidInstruction, diff --git a/src/interpreter.rs b/src/interpreter.rs index cb067978..529d59b5 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -22,11 +22,10 @@ use std::convert::TryInto; /// Virtual memory operation helper. macro_rules! translate_memory_access { - (_impl, $self:ident, $op:ident, $vm_addr:ident, $pc:ident, $T:ty, $($rest:expr),*) => { + (_impl, $self:ident, $op:ident, $vm_addr:ident, $T:ty, $($rest:expr),*) => { match $self.vm.memory_mapping.$op::<$T>( $($rest,)* $vm_addr, - $pc + ebpf::ELF_INSN_DUMP_OFFSET, ) { ProgramResult::Ok(v) => v, ProgramResult::Err(err) => { @@ -37,13 +36,13 @@ macro_rules! translate_memory_access { }; // MemoryMapping::load() - ($self:ident, load, $vm_addr:ident, $pc:ident, $T:ty) => { - translate_memory_access!(_impl, $self, load, $vm_addr, $pc, $T,) + ($self:ident, load, $vm_addr:ident, $T:ty) => { + translate_memory_access!(_impl, $self, load, $vm_addr, $T,) }; // MemoryMapping::store() - ($self:ident, store, $value:expr, $vm_addr:ident, $pc:ident, $T:ty) => { - translate_memory_access!(_impl, $self, store, $vm_addr, $pc, $T, ($value) as $T); + ($self:ident, store, $value:expr, $vm_addr:ident, $T:ty) => { + translate_memory_access!(_impl, $self, store, $vm_addr, $T, ($value) as $T); }; } @@ -202,55 +201,55 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { // BPF_LDX class ebpf::LD_B_REG => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; - self.reg[dst] = translate_memory_access!(self, load, vm_addr, pc, u8); + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u8); }, ebpf::LD_H_REG => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; - self.reg[dst] = translate_memory_access!(self, load, vm_addr, pc, u16); + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u16); }, ebpf::LD_W_REG => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; - self.reg[dst] = translate_memory_access!(self, load, vm_addr, pc, u32); + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u32); }, ebpf::LD_DW_REG => { let vm_addr = (self.reg[src] as i64).wrapping_add(insn.off as i64) as u64; - self.reg[dst] = translate_memory_access!(self, load, vm_addr, pc, u64); + self.reg[dst] = translate_memory_access!(self, load, vm_addr, u64); }, // BPF_ST class ebpf::ST_B_IMM => { let vm_addr = (self.reg[dst] as i64).wrapping_add( insn.off as i64) as u64; - translate_memory_access!(self, store, insn.imm, vm_addr, pc, u8); + translate_memory_access!(self, store, insn.imm, vm_addr, u8); }, ebpf::ST_H_IMM => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, insn.imm, vm_addr, pc, u16); + translate_memory_access!(self, store, insn.imm, vm_addr, u16); }, ebpf::ST_W_IMM => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, insn.imm, vm_addr, pc, u32); + translate_memory_access!(self, store, insn.imm, vm_addr, u32); }, ebpf::ST_DW_IMM => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, insn.imm, vm_addr, pc, u64); + translate_memory_access!(self, store, insn.imm, vm_addr, u64); }, // BPF_STX class ebpf::ST_B_REG => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, self.reg[src], vm_addr, pc, u8); + translate_memory_access!(self, store, self.reg[src], vm_addr, u8); }, ebpf::ST_H_REG => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, self.reg[src], vm_addr, pc, u16); + translate_memory_access!(self, store, self.reg[src], vm_addr, u16); }, ebpf::ST_W_REG => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, self.reg[src], vm_addr, pc, u32); + translate_memory_access!(self, store, self.reg[src], vm_addr, u32); }, ebpf::ST_DW_REG => { let vm_addr = (self.reg[dst] as i64).wrapping_add(insn.off as i64) as u64; - translate_memory_access!(self, store, self.reg[src], vm_addr, pc, u64); + translate_memory_access!(self, store, self.reg[src], vm_addr, u64); }, // BPF_ALU class diff --git a/src/jit.rs b/src/jit.rs index 36eb809e..c91e1e5f 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -181,22 +181,21 @@ impl PartialEq for JitProgram { // Used to define subroutines and then call them // See JitCompiler::set_anchor() and JitCompiler::relative_to_anchor() const ANCHOR_TRACE: usize = 0; -const ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS: usize = 1; +const ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS: usize = 1; const ANCHOR_EPILOGUE: usize = 2; const ANCHOR_THROW_EXCEPTION_UNCHECKED: usize = 3; const ANCHOR_EXIT: usize = 4; const ANCHOR_THROW_EXCEPTION: usize = 5; -const ANCHOR_ACCESS_VIOLATION: usize = 6; -const ANCHOR_CALL_DEPTH_EXCEEDED: usize = 7; -const ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT: usize = 8; -const ANCHOR_DIV_BY_ZERO: usize = 9; -const ANCHOR_DIV_OVERFLOW: usize = 10; -const ANCHOR_CALL_UNSUPPORTED_INSTRUCTION: usize = 11; -const ANCHOR_EXTERNAL_FUNCTION_CALL: usize = 12; -const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE: usize = 13; -const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_REG: usize = 14; -const ANCHOR_TRANSLATE_MEMORY_ADDRESS: usize = 22; -const ANCHOR_COUNT: usize = 31; // Update me when adding or removing anchors +const ANCHOR_CALL_DEPTH_EXCEEDED: usize = 6; +const ANCHOR_CALL_OUTSIDE_TEXT_SEGMENT: usize = 7; +const ANCHOR_DIV_BY_ZERO: usize = 8; +const ANCHOR_DIV_OVERFLOW: usize = 9; +const ANCHOR_CALL_UNSUPPORTED_INSTRUCTION: usize = 10; +const ANCHOR_EXTERNAL_FUNCTION_CALL: usize = 11; +const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_PROLOGUE: usize = 12; +const ANCHOR_ANCHOR_INTERNAL_FUNCTION_CALL_REG: usize = 13; +const ANCHOR_TRANSLATE_MEMORY_ADDRESS: usize = 21; +const ANCHOR_COUNT: usize = 30; // Update me when adding or removing anchors const REGISTER_MAP: [u8; 11] = [ CALLER_SAVED_REGISTERS[0], @@ -215,8 +214,8 @@ const REGISTER_MAP: [u8; 11] = [ // Special registers: // ARGUMENT_REGISTERS[0] RDI BPF program counter limit (used by instruction meter) // CALLER_SAVED_REGISTERS[8] R11 Scratch register -// CALLER_SAVED_REGISTERS[7] R10 Unused for the most part, scratch register for exception handling -// CALLEE_SAVED_REGISTERS[0] RBP Constant pointer to initial RSP - 8 +// CALLER_SAVED_REGISTERS[7] R10 Scratch register +// CALLEE_SAVED_REGISTERS[0] RBP Constant pointer to vm object, see slot_on_environment_stack() #[derive(Copy, Clone, Debug)] pub enum OperandSize { @@ -876,7 +875,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { } else { self.emit_ins(X86Instruction::cmp(OperandSize::S64, R11, ARGUMENT_REGISTERS[0], None)); } - self.emit_ins(X86Instruction::conditional_jump_immediate(if exclusive { 0x82 } else { 0x86 }, self.relative_to_anchor(ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS, 6))); + self.emit_ins(X86Instruction::conditional_jump_immediate(if exclusive { 0x82 } else { 0x86 }, self.relative_to_anchor(ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS, 6))); } #[inline] @@ -1285,9 +1284,9 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { fn emit_set_exception_kind(&mut self, err: EbpfError) { let err_kind = unsafe { *(&err as *const _ as *const u64) }; let err_discriminant = ProgramResult::Err(err).discriminant(); - self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32)))); - self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(-(std::mem::size_of::() as i32)), err_discriminant as i64)); // result.discriminant = err_discriminant; - self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(0), err_kind as i64)); // err.kind = err_kind; + self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult))))); + self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(0), err_discriminant as i64)); // result.discriminant = err_discriminant; + self.emit_ins(X86Instruction::store_immediate(OperandSize::S64, R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32), err_kind as i64)); // err.kind = err_kind; } fn emit_result_is_err(&mut self, destination: u8) { @@ -1341,7 +1340,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_ins(X86Instruction::return_near()); // Handler for EbpfError::ExceededMaxInstructions - self.set_anchor(ANCHOR_CALL_EXCEEDED_MAX_INSTRUCTIONS); + self.set_anchor(ANCHOR_THROW_EXCEEDED_MAX_INSTRUCTIONS); self.emit_set_exception_kind(EbpfError::ExceededMaxInstructions); self.emit_ins(X86Instruction::mov(OperandSize::S64, ARGUMENT_REGISTERS[0], R11)); // R11 = instruction_meter; // Fall through @@ -1354,7 +1353,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.set_anchor(ANCHOR_EXIT); self.emit_validate_instruction_count(false, None); self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult))))); - self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[0], R10, X86IndirectAccess::Offset(8))); // result.return_value = R0; + self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_MAP[0], R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32))); // result.return_value = R0; self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, REGISTER_MAP[0], 0)); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_EPILOGUE, 5))); @@ -1364,12 +1363,6 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_validate_instruction_count(false, None); self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION_UNCHECKED, 5))); - // Handler for EbpfError::AccessViolation - self.set_anchor(ANCHOR_ACCESS_VIOLATION); - self.emit_ins(X86Instruction::store(OperandSize::S64, R11, R10, X86IndirectAccess::Offset(std::mem::size_of::() as i32 * 2))); // result.pc = self.pc; - self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x81, 0, R10, ebpf::ELF_INSN_DUMP_OFFSET as i64, Some(X86IndirectAccess::Offset(std::mem::size_of::() as i32 * 2)))); // result.pc += ebpf::ELF_INSN_DUMP_OFFSET; - self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 5))); - // Handler for EbpfError::CallDepthExceeded self.set_anchor(ANCHOR_CALL_DEPTH_EXCEEDED); self.emit_set_exception_kind(EbpfError::CallDepthExceeded); @@ -1547,11 +1540,10 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_result_is_err(R11); self.emit_ins(X86Instruction::pop(R11)); // R11 = self.pc self.emit_ins(X86Instruction::xchg(OperandSize::S64, R11, RSP, Some(X86IndirectAccess::OffsetIndexShift(0, RSP, 0)))); // Swap return address and self.pc - self.emit_ins(X86Instruction::lea(OperandSize::S64, RBP, R10, Some(X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult))))); - self.emit_ins(X86Instruction::conditional_jump_immediate(0x85, self.relative_to_anchor(ANCHOR_ACCESS_VIOLATION, 6))); + self.emit_ins(X86Instruction::conditional_jump_immediate(0x85, self.relative_to_anchor(ANCHOR_THROW_EXCEPTION, 6))); // unwrap() the result into R11 - self.emit_ins(X86Instruction::load(OperandSize::S64, R10, R11, X86IndirectAccess::Offset(8))); + self.emit_ins(X86Instruction::load(OperandSize::S64, RBP, R11, X86IndirectAccess::Offset(self.slot_on_environment_stack(RuntimeEnvironmentSlot::ProgramResult) + std::mem::size_of::() as i32))); self.emit_ins(X86Instruction::return_near()); } diff --git a/src/memory_region.rs b/src/memory_region.rs index 367d614d..9f519f2d 100644 --- a/src/memory_region.rs +++ b/src/memory_region.rs @@ -330,7 +330,7 @@ impl<'a> UnalignedMemoryMapping<'a> { } /// Given a list of regions translate from virtual machine to host address - pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64, pc: usize) -> ProgramResult { + pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64) -> ProgramResult { // Safety: // &mut references to the mapping cache are only created internally from methods that do not // invoke each other. UnalignedMemoryMapping is !Sync, so the cache reference below is @@ -346,7 +346,6 @@ impl<'a> UnalignedMemoryMapping<'a> { access_type, vm_addr, len, - pc, ) } }; @@ -357,21 +356,14 @@ impl<'a> UnalignedMemoryMapping<'a> { } } - generate_access_violation( - self.config, - self.sbpf_version, - access_type, - vm_addr, - len, - pc, - ) + generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, len) } /// Loads `size_of::()` bytes from the given address. /// /// See [MemoryMapping::load]. #[inline(always)] - pub fn load>(&self, mut vm_addr: u64, pc: usize) -> ProgramResult { + pub fn load>(&self, mut vm_addr: u64) -> ProgramResult { let mut len = mem::size_of::() as u64; debug_assert!(len <= mem::size_of::() as u64); @@ -399,7 +391,6 @@ impl<'a> UnalignedMemoryMapping<'a> { AccessType::Load, vm_addr, len, - pc, ) } }; @@ -443,7 +434,6 @@ impl<'a> UnalignedMemoryMapping<'a> { AccessType::Load, initial_vm_addr, initial_len, - pc, ) } @@ -451,7 +441,7 @@ impl<'a> UnalignedMemoryMapping<'a> { /// /// See [MemoryMapping::store]. #[inline] - pub fn store(&self, value: T, mut vm_addr: u64, pc: usize) -> ProgramResult { + pub fn store(&self, value: T, mut vm_addr: u64) -> ProgramResult { let mut len = mem::size_of::() as u64; // Safety: @@ -481,7 +471,6 @@ impl<'a> UnalignedMemoryMapping<'a> { AccessType::Store, vm_addr, len, - pc, ) } }; @@ -524,7 +513,6 @@ impl<'a> UnalignedMemoryMapping<'a> { AccessType::Store, initial_vm_addr, initial_len, - pc, ) } @@ -547,7 +535,7 @@ impl<'a> UnalignedMemoryMapping<'a> { } } Err( - generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, 0, 0) + generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, 0) .unwrap_err(), ) } @@ -647,7 +635,7 @@ impl<'a> AlignedMemoryMapping<'a> { } /// Given a list of regions translate from virtual machine to host address - pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64, pc: usize) -> ProgramResult { + pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64) -> ProgramResult { let index = vm_addr .checked_shr(ebpf::VIRTUAL_ADDRESS_BITS as u32) .unwrap_or(0) as usize; @@ -659,23 +647,16 @@ impl<'a> AlignedMemoryMapping<'a> { } } } - generate_access_violation( - self.config, - self.sbpf_version, - access_type, - vm_addr, - len, - pc, - ) + generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, len) } /// Loads `size_of::()` bytes from the given address. /// /// See [MemoryMapping::load]. #[inline] - pub fn load>(&self, vm_addr: u64, pc: usize) -> ProgramResult { + pub fn load>(&self, vm_addr: u64) -> ProgramResult { let len = mem::size_of::() as u64; - match self.map(AccessType::Load, vm_addr, len, pc) { + match self.map(AccessType::Load, vm_addr, len) { ProgramResult::Ok(host_addr) => { ProgramResult::Ok(unsafe { ptr::read_unaligned::(host_addr as *const _) }.into()) } @@ -687,11 +668,11 @@ impl<'a> AlignedMemoryMapping<'a> { /// /// See [MemoryMapping::store]. #[inline] - pub fn store(&self, value: T, vm_addr: u64, pc: usize) -> ProgramResult { + pub fn store(&self, value: T, vm_addr: u64) -> ProgramResult { let len = mem::size_of::() as u64; debug_assert!(len <= mem::size_of::() as u64); - match self.map(AccessType::Store, vm_addr, len, pc) { + match self.map(AccessType::Store, vm_addr, len) { ProgramResult::Ok(host_addr) => { // Safety: // map succeeded so we can write at least `len` bytes @@ -723,7 +704,7 @@ impl<'a> AlignedMemoryMapping<'a> { } } Err( - generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, 0, 0) + generate_access_violation(self.config, self.sbpf_version, access_type, vm_addr, 0) .unwrap_err(), ) } @@ -808,11 +789,11 @@ impl<'a> MemoryMapping<'a> { } /// Map virtual memory to host memory. - pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64, pc: usize) -> ProgramResult { + pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64) -> ProgramResult { match self { MemoryMapping::Identity => ProgramResult::Ok(vm_addr), - MemoryMapping::Aligned(m) => m.map(access_type, vm_addr, len, pc), - MemoryMapping::Unaligned(m) => m.map(access_type, vm_addr, len, pc), + MemoryMapping::Aligned(m) => m.map(access_type, vm_addr, len), + MemoryMapping::Unaligned(m) => m.map(access_type, vm_addr, len), } } @@ -820,13 +801,13 @@ impl<'a> MemoryMapping<'a> { /// /// Works across memory region boundaries. #[inline] - pub fn load>(&self, vm_addr: u64, pc: usize) -> ProgramResult { + pub fn load>(&self, vm_addr: u64) -> ProgramResult { match self { MemoryMapping::Identity => unsafe { ProgramResult::Ok(ptr::read_unaligned(vm_addr as *const T).into()) }, - MemoryMapping::Aligned(m) => m.load::(vm_addr, pc), - MemoryMapping::Unaligned(m) => m.load::(vm_addr, pc), + MemoryMapping::Aligned(m) => m.load::(vm_addr), + MemoryMapping::Unaligned(m) => m.load::(vm_addr), } } @@ -834,14 +815,14 @@ impl<'a> MemoryMapping<'a> { /// /// Works across memory region boundaries if `len` does not fit within a single region. #[inline] - pub fn store(&self, value: T, vm_addr: u64, pc: usize) -> ProgramResult { + pub fn store(&self, value: T, vm_addr: u64) -> ProgramResult { match self { MemoryMapping::Identity => unsafe { ptr::write_unaligned(vm_addr as *mut T, value); ProgramResult::Ok(0) }, - MemoryMapping::Aligned(m) => m.store(value, vm_addr, pc), - MemoryMapping::Unaligned(m) => m.store(value, vm_addr, pc), + MemoryMapping::Aligned(m) => m.store(value, vm_addr), + MemoryMapping::Unaligned(m) => m.store(value, vm_addr), } } @@ -902,7 +883,6 @@ fn generate_access_violation( access_type: AccessType, vm_addr: u64, len: u64, - pc: usize, ) -> ProgramResult { let stack_frame = (vm_addr as i64) .saturating_sub(ebpf::MM_STACK_START as i64) @@ -912,7 +892,6 @@ fn generate_access_violation( && (-1..(config.max_call_depth as i64).saturating_add(1)).contains(&stack_frame) { ProgramResult::Err(EbpfError::StackAccessViolation( - pc, access_type, vm_addr, len, @@ -927,7 +906,6 @@ fn generate_access_violation( _ => "unknown", }; ProgramResult::Err(EbpfError::AccessViolation( - pc, access_type, vm_addr, len, @@ -1060,13 +1038,13 @@ mod test { let config = Config::default(); let m = UnalignedMemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); assert_error!( - m.map(AccessType::Load, ebpf::MM_INPUT_START, 8, 0), + m.map(AccessType::Load, ebpf::MM_INPUT_START, 8), "AccessViolation" ); let m = AlignedMemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); assert_error!( - m.map(AccessType::Load, ebpf::MM_INPUT_START, 8, 0), + m.map(AccessType::Load, ebpf::MM_INPUT_START, 8), "AccessViolation" ); } @@ -1091,15 +1069,12 @@ mod test { for frame in 0..4 { let address = ebpf::MM_STACK_START + frame * 4; assert!(m.region(AccessType::Load, address).is_ok()); - assert!(m.map(AccessType::Load, address, 2, 0).is_ok()); - assert_error!( - m.map(AccessType::Load, address + 2, 2, 0), - "AccessViolation" - ); - assert_eq!(m.load::(address, 0).unwrap(), 0xFFFF); - assert_error!(m.load::(address + 2, 0), "AccessViolation"); - assert!(m.store::(0xFFFF, address, 0).is_ok()); - assert_error!(m.store::(0xFFFF, address + 2, 0), "AccessViolation"); + assert!(m.map(AccessType::Load, address, 2).is_ok()); + assert_error!(m.map(AccessType::Load, address + 2, 2), "AccessViolation"); + assert_eq!(m.load::(address).unwrap(), 0xFFFF); + assert_error!(m.load::(address + 2), "AccessViolation"); + assert!(m.store::(0xFFFF, address).is_ok()); + assert_error!(m.store::(0xFFFF, address + 2), "AccessViolation"); } } } @@ -1157,18 +1132,17 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_INPUT_START, 1, 0).unwrap(), + m.map(AccessType::Load, ebpf::MM_INPUT_START, 1).unwrap(), mem1.as_ptr() as u64 ); assert_eq!( - m.map(AccessType::Store, ebpf::MM_INPUT_START, 1, 0) - .unwrap(), + m.map(AccessType::Store, ebpf::MM_INPUT_START, 1).unwrap(), mem1.as_ptr() as u64 ); assert_error!( - m.map(AccessType::Load, ebpf::MM_INPUT_START, 2, 0), + m.map(AccessType::Load, ebpf::MM_INPUT_START, 2), "AccessViolation" ); @@ -1177,7 +1151,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + mem1.len() as u64, 1, - 0, ) .unwrap(), mem2.as_ptr() as u64 @@ -1188,7 +1161,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + (mem1.len() + mem2.len()) as u64, 1, - 0, ) .unwrap(), mem3.as_ptr() as u64 @@ -1199,7 +1171,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + (mem1.len() + mem2.len() + mem3.len()) as u64, 1, - 0, ) .unwrap(), mem4.as_ptr() as u64 @@ -1210,7 +1181,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + (mem1.len() + mem2.len() + mem3.len() + mem4.len()) as u64, 1, - 0, ), "AccessViolation" ); @@ -1369,19 +1339,16 @@ mod test { ) .unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x2211); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x44332211); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x2211); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x44332211); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0x8877665544332211 ); - assert_eq!(m.load::(ebpf::MM_INPUT_START + 1, 0).unwrap(), 0x3322); - assert_eq!( - m.load::(ebpf::MM_INPUT_START + 1, 0).unwrap(), - 0x55443322 - ); + assert_eq!(m.load::(ebpf::MM_INPUT_START + 1).unwrap(), 0x3322); + assert_eq!(m.load::(ebpf::MM_INPUT_START + 1).unwrap(), 0x55443322); assert_eq!( - m.load::(ebpf::MM_INPUT_START + 1, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START + 1).unwrap(), 0x9988776655443322 ); } @@ -1413,16 +1380,16 @@ mod test { &SBPFVersion::V2, ) .unwrap(); - m.store(0x1122u16, ebpf::MM_INPUT_START, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x1122); + m.store(0x1122u16, ebpf::MM_INPUT_START).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x1122); - m.store(0x33445566u32, ebpf::MM_INPUT_START, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x33445566); + m.store(0x33445566u32, ebpf::MM_INPUT_START).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x33445566); - m.store(0x778899AABBCCDDEEu64, ebpf::MM_INPUT_START, 0) + m.store(0x778899AABBCCDDEEu64, ebpf::MM_INPUT_START) .unwrap(); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0x778899AABBCCDDEE ); } @@ -1441,20 +1408,20 @@ mod test { ) .unwrap(); - m.store(0x1122334455667788u64, ebpf::MM_INPUT_START, 0) + m.store(0x1122334455667788u64, ebpf::MM_INPUT_START) .unwrap(); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0x1122334455667788 ); - m.store(0x22334455u32, ebpf::MM_INPUT_START, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x22334455); + m.store(0x22334455u32, ebpf::MM_INPUT_START).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x22334455); - m.store(0x3344u16, ebpf::MM_INPUT_START, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x3344); + m.store(0x3344u16, ebpf::MM_INPUT_START).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x3344); - m.store(0x55u8, ebpf::MM_INPUT_START, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0x55); + m.store(0x55u8, ebpf::MM_INPUT_START).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0x55); } #[test] @@ -1475,20 +1442,17 @@ mod test { ) .unwrap(); - m.store(0x1122334455667788u64, ebpf::MM_INPUT_START, 0) + m.store(0x1122334455667788u64, ebpf::MM_INPUT_START) .unwrap(); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0x1122334455667788 ); - m.store(0xAABBCCDDu32, ebpf::MM_INPUT_START + 4, 0).unwrap(); - assert_eq!( - m.load::(ebpf::MM_INPUT_START + 4, 0).unwrap(), - 0xAABBCCDD - ); + m.store(0xAABBCCDDu32, ebpf::MM_INPUT_START + 4).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START + 4).unwrap(), 0xAABBCCDD); - m.store(0xEEFFu16, ebpf::MM_INPUT_START + 6, 0).unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START + 6, 0).unwrap(), 0xEEFF); + m.store(0xEEFFu16, ebpf::MM_INPUT_START + 6).unwrap(); + assert_eq!(m.load::(ebpf::MM_INPUT_START + 6).unwrap(), 0xEEFF); } #[test] @@ -1505,21 +1469,12 @@ mod test { &SBPFVersion::V2, ) .unwrap(); - m.store(0x11u8, ebpf::MM_INPUT_START, 0).unwrap(); - assert_error!( - m.store(0x11u8, ebpf::MM_INPUT_START - 1, 0), - "AccessViolation" - ); - assert_error!( - m.store(0x11u8, ebpf::MM_INPUT_START + 1, 0), - "AccessViolation" - ); + m.store(0x11u8, ebpf::MM_INPUT_START).unwrap(); + assert_error!(m.store(0x11u8, ebpf::MM_INPUT_START - 1), "AccessViolation"); + assert_error!(m.store(0x11u8, ebpf::MM_INPUT_START + 1), "AccessViolation"); // this gets us line coverage for the case where we're completely // outside the address space (the case above is just on the edge) - assert_error!( - m.store(0x11u8, ebpf::MM_INPUT_START + 2, 0), - "AccessViolation" - ); + assert_error!(m.store(0x11u8, ebpf::MM_INPUT_START + 2), "AccessViolation"); let mut mem1 = vec![0xFF; 4]; let mut mem2 = vec![0xDD; 4]; @@ -1532,14 +1487,14 @@ mod test { &SBPFVersion::V2, ) .unwrap(); - m.store(0x1122334455667788u64, ebpf::MM_INPUT_START, 0) + m.store(0x1122334455667788u64, ebpf::MM_INPUT_START) .unwrap(); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0x1122334455667788u64 ); assert_error!( - m.store(0x1122334455667788u64, ebpf::MM_INPUT_START + 1, 0), + m.store(0x1122334455667788u64, ebpf::MM_INPUT_START + 1), "AccessViolation" ); } @@ -1558,10 +1513,10 @@ mod test { &SBPFVersion::V2, ) .unwrap(); - assert_eq!(m.load::(ebpf::MM_INPUT_START, 0).unwrap(), 0xff); - assert_error!(m.load::(ebpf::MM_INPUT_START - 1, 0), "AccessViolation"); - assert_error!(m.load::(ebpf::MM_INPUT_START + 1, 0), "AccessViolation"); - assert_error!(m.load::(ebpf::MM_INPUT_START + 2, 0), "AccessViolation"); + assert_eq!(m.load::(ebpf::MM_INPUT_START).unwrap(), 0xff); + assert_error!(m.load::(ebpf::MM_INPUT_START - 1), "AccessViolation"); + assert_error!(m.load::(ebpf::MM_INPUT_START + 1), "AccessViolation"); + assert_error!(m.load::(ebpf::MM_INPUT_START + 2), "AccessViolation"); let mem1 = vec![0xFF; 4]; let mem2 = vec![0xDD; 4]; @@ -1575,13 +1530,10 @@ mod test { ) .unwrap(); assert_eq!( - m.load::(ebpf::MM_INPUT_START, 0).unwrap(), + m.load::(ebpf::MM_INPUT_START).unwrap(), 0xDDDDDDDDFFFFFFFF ); - assert_error!( - m.load::(ebpf::MM_INPUT_START + 1, 0), - "AccessViolation" - ); + assert_error!(m.load::(ebpf::MM_INPUT_START + 1), "AccessViolation"); } #[test] @@ -1602,7 +1554,7 @@ mod test { &SBPFVersion::V2, ) .unwrap(); - m.store(0x11223344, ebpf::MM_INPUT_START, 0).unwrap(); + m.store(0x11223344, ebpf::MM_INPUT_START).unwrap(); } #[test] @@ -1622,7 +1574,7 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_INPUT_START, 1, 0).unwrap(), + m.map(AccessType::Load, ebpf::MM_INPUT_START, 1).unwrap(), mem1.as_ptr() as u64 ); @@ -1631,7 +1583,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + mem1.len() as u64, 1, - 0, ) .unwrap(), mem2.as_ptr() as u64 @@ -1672,7 +1623,6 @@ mod test { AccessType::Load, ebpf::MM_INPUT_START + mem1.len() as u64, 1, - 0, ) .unwrap(), mem3.as_ptr() as u64 @@ -1696,7 +1646,7 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_STACK_START, 1, 0).unwrap(), + m.map(AccessType::Load, ebpf::MM_STACK_START, 1).unwrap(), mem2.as_ptr() as u64 ); @@ -1725,7 +1675,7 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_STACK_START, 1, 0).unwrap(), + m.map(AccessType::Load, ebpf::MM_STACK_START, 1).unwrap(), mem3.as_ptr() as u64 ); } @@ -1753,13 +1703,11 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_PROGRAM_START, 1, 0) - .unwrap(), + m.map(AccessType::Load, ebpf::MM_PROGRAM_START, 1).unwrap(), original.as_ptr() as u64 ); assert_eq!( - m.map(AccessType::Store, ebpf::MM_PROGRAM_START, 1, 0) - .unwrap(), + m.map(AccessType::Store, ebpf::MM_PROGRAM_START, 1).unwrap(), copied.borrow().as_ptr() as u64 ); } @@ -1788,19 +1736,18 @@ mod test { .unwrap(); assert_eq!( - m.map(AccessType::Load, ebpf::MM_PROGRAM_START, 1, 0) - .unwrap(), + m.map(AccessType::Load, ebpf::MM_PROGRAM_START, 1).unwrap(), original.as_ptr() as u64 ); - assert_eq!(m.load::(ebpf::MM_PROGRAM_START, 0).unwrap(), 11); - assert_eq!(m.load::(ebpf::MM_PROGRAM_START + 1, 0).unwrap(), 22); + assert_eq!(m.load::(ebpf::MM_PROGRAM_START).unwrap(), 11); + assert_eq!(m.load::(ebpf::MM_PROGRAM_START + 1).unwrap(), 22); assert!(copied.borrow().is_empty()); - m.store(33u8, ebpf::MM_PROGRAM_START, 0).unwrap(); + m.store(33u8, ebpf::MM_PROGRAM_START).unwrap(); assert_eq!(original[0], 11); - assert_eq!(m.load::(ebpf::MM_PROGRAM_START, 0).unwrap(), 33); - assert_eq!(m.load::(ebpf::MM_PROGRAM_START + 1, 0).unwrap(), 22); + assert_eq!(m.load::(ebpf::MM_PROGRAM_START).unwrap(), 33); + assert_eq!(m.load::(ebpf::MM_PROGRAM_START + 1).unwrap(), 22); } } @@ -1833,9 +1780,9 @@ mod test { ) .unwrap(); - m.store(55u8, ebpf::MM_PROGRAM_START, 0).unwrap(); + m.store(55u8, ebpf::MM_PROGRAM_START).unwrap(); assert_eq!(original1[0], 11); - assert_eq!(m.load::(ebpf::MM_PROGRAM_START, 0).unwrap(), 55); + assert_eq!(m.load::(ebpf::MM_PROGRAM_START).unwrap(), 55); } } @@ -1853,8 +1800,7 @@ mod test { ) .unwrap(); - m.map(AccessType::Store, ebpf::MM_PROGRAM_START, 1, 0) - .unwrap(); + m.map(AccessType::Store, ebpf::MM_PROGRAM_START, 1).unwrap(); } #[test] @@ -1871,6 +1817,6 @@ mod test { ) .unwrap(); - m.store(33u8, ebpf::MM_PROGRAM_START, 0).unwrap(); + m.store(33u8, ebpf::MM_PROGRAM_START).unwrap(); } } diff --git a/src/syscalls.rs b/src/syscalls.rs index 53aa35a0..df8c805a 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -176,10 +176,7 @@ pub fn bpf_mem_frob( memory_mapping: &mut MemoryMapping, result: &mut ProgramResult, ) { - let host_addr = question_mark!( - memory_mapping.map(AccessType::Store, vm_addr, len, 0), - result - ); + let host_addr = question_mark!(memory_mapping.map(AccessType::Store, vm_addr, len), result); for i in 0..len { unsafe { let p = (host_addr + i) as *mut u8; @@ -226,8 +223,8 @@ pub fn bpf_str_cmp( *result = ProgramResult::Ok(u64::MAX); return; } - let mut a = question_mark!(memory_mapping.map(AccessType::Load, arg1, 1, 0), result); - let mut b = question_mark!(memory_mapping.map(AccessType::Load, arg2, 1, 0), result); + let mut a = question_mark!(memory_mapping.map(AccessType::Load, arg1, 1), result); + let mut b = question_mark!(memory_mapping.map(AccessType::Load, arg2, 1), result); unsafe { let mut a_val = *(a as *const u8); let mut b_val = *(b as *const u8); @@ -258,10 +255,7 @@ pub fn bpf_syscall_string( memory_mapping: &mut MemoryMapping, result: &mut ProgramResult, ) { - let host_addr = question_mark!( - memory_mapping.map(AccessType::Load, vm_addr, len, 0), - result - ); + let host_addr = question_mark!(memory_mapping.map(AccessType::Load, vm_addr, len), result); let c_buf: *const i8 = host_addr as *const i8; unsafe { for i in 0..len { diff --git a/tests/execution.rs b/tests/execution.rs index 06ddae37..33c4ba87 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -892,7 +892,6 @@ fn test_err_ldxdw_oob() { (), TestContextObject::new(1), ProgramResult::Err(EbpfError::AccessViolation( - 29, AccessType::Load, 0x400000006, 8, @@ -911,7 +910,6 @@ fn test_err_ldxdw_nomem() { (), TestContextObject::new(1), ProgramResult::Err(EbpfError::AccessViolation( - 29, AccessType::Load, 0x400000006, 8, @@ -1959,7 +1957,6 @@ fn test_err_dynamic_stack_out_of_bound() { (), TestContextObject::new(1), ProgramResult::Err(EbpfError::AccessViolation( - 29, AccessType::Store, ebpf::MM_STACK_START - 1, 1, @@ -1977,7 +1974,6 @@ fn test_err_dynamic_stack_out_of_bound() { (), TestContextObject::new(1), ProgramResult::Err(EbpfError::AccessViolation( - 29, AccessType::Store, ebpf::MM_STACK_START + config.stack_size() as u64, 1, @@ -2011,7 +2007,6 @@ fn test_err_dynamic_stack_ptr_overflow() { (), TestContextObject::new(7), ProgramResult::Err(EbpfError::AccessViolation( - 36, AccessType::Store, u64::MAX, 1, @@ -2188,7 +2183,6 @@ fn test_err_mem_access_out_of_bound() { mem, TestContextObject::new(3), ProgramResult::Err(EbpfError::AccessViolation( - 31, AccessType::Store, address, 1, @@ -2418,7 +2412,7 @@ fn test_err_syscall_string() { "bpf_syscall_string" => syscalls::bpf_syscall_string, ), TestContextObject::new(2), - ProgramResult::Err(EbpfError::AccessViolation(0, AccessType::Load, 0, 0, "unknown")), + ProgramResult::Err(EbpfError::AccessViolation(AccessType::Load, 0, 0, "unknown")), ); } @@ -3413,7 +3407,6 @@ fn test_err_fixed_stack_out_of_bound() { (), TestContextObject::new(1), ProgramResult::Err(EbpfError::AccessViolation( - 29, AccessType::Store, 0x1FFFFD000, 1,