Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Also removes the pc field from EbpfError::AccessViolation.
Browse files Browse the repository at this point in the history
Lichtso committed Sep 28, 2023
1 parent 7d21297 commit ee0a0c4
Showing 7 changed files with 128 additions and 210 deletions.
4 changes: 1 addition & 3 deletions src/debugger.rs
Original file line number Diff line number Diff line change
@@ -152,7 +152,6 @@ impl<'a, 'b, C: ContextObject> Target for Interpreter<'a, 'b, C> {
fn get_host_ptr<C: ContextObject>(
interpreter: &mut Interpreter<C>,
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<C: ContextObject>(
AccessType::Load,
vm_addr,
std::mem::size_of::<u8>() 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,
12 changes: 4 additions & 8 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -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,
35 changes: 17 additions & 18 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -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
36 changes: 14 additions & 22 deletions src/jit.rs
Original file line number Diff line number Diff line change
@@ -186,17 +186,16 @@ 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 {
@@ -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::<u64>() 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::<u64>() 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::<u64>() as i32)));

self.emit_ins(X86Instruction::return_near());
}
228 changes: 87 additions & 141 deletions src/memory_region.rs

Large diffs are not rendered by default.

14 changes: 4 additions & 10 deletions src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -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 {
9 changes: 1 addition & 8 deletions tests/execution.rs
Original file line number Diff line number Diff line change
@@ -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,

0 comments on commit ee0a0c4

Please sign in to comment.