Skip to content

Commit

Permalink
Removes all fields from runtime errors, leaving only the discriminant.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Sep 29, 2023
1 parent d87f8ff commit e2c048b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 137 deletions.
34 changes: 16 additions & 18 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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),
Expand Down
101 changes: 40 additions & 61 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};
}
Expand Down Expand Up @@ -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)
Expand All @@ -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);
}
}

Expand All @@ -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() {
Expand All @@ -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;
Expand All @@ -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;
},
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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);
}
};
},
Expand All @@ -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);
}
};
},
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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;
},

Expand Down Expand Up @@ -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);
}
},

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
Loading

0 comments on commit e2c048b

Please sign in to comment.