From 9b1d33fcdb867b1b68e6dcb903e9f6a40578a382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Sat, 30 Sep 2023 17:23:19 +0200 Subject: [PATCH] Puts due_insn_count into the VM. --- src/interpreter.rs | 14 ++++++-------- src/jit.rs | 14 ++++++++------ src/program.rs | 2 +- src/vm.rs | 14 +++++++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 93b2b10d..2d485ba0 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -91,7 +91,6 @@ pub struct Interpreter<'a, 'b, C: ContextObject> { pub(crate) executable: &'a Executable, pub(crate) program: &'a [u8], pub(crate) program_vm_addr: u64, - pub(crate) due_insn_count: u64, /// General purpose registers and pc pub reg: [u64; 12], @@ -115,7 +114,6 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { executable, program, program_vm_addr, - due_insn_count: 0, reg: registers, #[cfg(feature = "debugger")] debug_state: DebugState::Continue, @@ -161,7 +159,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { pub fn step(&mut self) -> bool { let config = &self.executable.get_config(); - self.due_insn_count += 1; + self.vm.due_insn_count += 1; let mut next_pc = self.reg[11] + 1; if next_pc as usize * ebpf::INSN_SIZE > self.program.len() { throw_error!(self, EbpfError::ExecutionOverrun); @@ -456,7 +454,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { } check_pc!(self, next_pc, (target_pc - self.program_vm_addr) / ebpf::INSN_SIZE as u64); if self.executable.get_sbpf_version().static_syscalls() && self.executable.get_function_registry().lookup_by_key(next_pc as u32).is_none() { - self.due_insn_count += 1; + self.vm.due_insn_count += 1; self.reg[11] = next_pc; throw_error!(self, EbpfError::UnsupportedInstruction); } @@ -476,8 +474,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { if let Some((_function_name, function)) = self.executable.get_loader().get_function_registry().lookup_by_key(insn.imm as u32) { resolved = true; - self.vm.previous_instruction_meter = self.due_insn_count; - self.due_insn_count = 0; + self.vm.due_insn_count = self.vm.previous_instruction_meter - self.vm.due_insn_count; function( unsafe { (self.vm as *mut _ as *mut u64).offset(get_runtime_environment_key() as isize) as *mut _ }, self.reg[1], @@ -486,6 +483,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { self.reg[4], self.reg[5], ); + self.vm.due_insn_count = 0; self.reg[0] = match &self.vm.program_result { ProgramResult::Ok(value) => *value, ProgramResult::Err(_err) => return false, @@ -512,7 +510,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { ebpf::EXIT => { if self.vm.call_depth == 0 { - if config.enable_instruction_meter && self.due_insn_count > self.vm.previous_instruction_meter { + if config.enable_instruction_meter && self.vm.due_insn_count > self.vm.previous_instruction_meter { throw_error!(self, EbpfError::ExceededMaxInstructions); } self.vm.program_result = ProgramResult::Ok(self.reg[0]); @@ -535,7 +533,7 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> { _ => throw_error!(self, EbpfError::UnsupportedInstruction), } - if config.enable_instruction_meter && self.due_insn_count >= self.vm.previous_instruction_meter { + if config.enable_instruction_meter && self.vm.due_insn_count >= self.vm.previous_instruction_meter { self.reg[11] += 1; throw_error!(self, EbpfError::ExceededMaxInstructions); } diff --git a/src/jit.rs b/src/jit.rs index 31331509..3e26a934 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -249,11 +249,12 @@ enum RuntimeEnvironmentSlot { StackPointer = 2, ContextObjectPointer = 3, PreviousInstructionMeter = 4, - StopwatchNumerator = 5, - StopwatchDenominator = 6, - Registers = 7, - ProgramResult = 19, - MemoryMapping = 27, + DueInsnCount = 5, + StopwatchNumerator = 6, + StopwatchDenominator = 7, + Registers = 8, + ProgramResult = 20, + MemoryMapping = 28, } /* Explaination of the Instruction Meter @@ -1386,7 +1387,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.set_anchor(ANCHOR_EXTERNAL_FUNCTION_CALL); self.emit_ins(X86Instruction::push_immediate(OperandSize::S64, -1)); // Used as PC value in error case, acts as stack padding otherwise if self.config.enable_instruction_meter { - self.emit_ins(X86Instruction::alu(OperandSize::S64, 0x29, REGISTER_INSTRUCTION_METER, REGISTER_PTR_TO_VM, 0, Some(X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::PreviousInstructionMeter))))); // *PreviousInstructionMeter -= REGISTER_INSTRUCTION_METER; + self.emit_ins(X86Instruction::store(OperandSize::S64, REGISTER_INSTRUCTION_METER, REGISTER_PTR_TO_VM, X86IndirectAccess::Offset(self.slot_in_vm(RuntimeEnvironmentSlot::DueInsnCount)))); // *DueInsnCount = REGISTER_INSTRUCTION_METER; } self.emit_rust_call(Value::Register(REGISTER_SCRATCH), &[ Argument { index: 5, value: Value::Register(ARGUMENT_REGISTERS[5]) }, @@ -1627,6 +1628,7 @@ mod tests { check_slot!(env, stack_pointer, StackPointer); check_slot!(env, context_object_pointer, ContextObjectPointer); check_slot!(env, previous_instruction_meter, PreviousInstructionMeter); + check_slot!(env, due_insn_count, DueInsnCount); check_slot!(env, stopwatch_numerator, StopwatchNumerator); check_slot!(env, stopwatch_denominator, StopwatchDenominator); check_slot!(env, registers, Registers); diff --git a/src/program.rs b/src/program.rs index 350587fe..add04970 100644 --- a/src/program.rs +++ b/src/program.rs @@ -310,7 +310,7 @@ macro_rules! declare_builtin_function { }; let config = vm.loader.get_config(); if config.enable_instruction_meter { - vm.context_object_pointer.consume(vm.previous_instruction_meter); + vm.context_object_pointer.consume(vm.previous_instruction_meter - vm.due_insn_count); } let converted_result: $crate::vm::ProgramResult = Self::rust( vm.context_object_pointer, arg_a, arg_b, arg_c, arg_d, arg_e, &mut vm.memory_mapping, diff --git a/src/vm.rs b/src/vm.rs index 88f67cad..73a1250b 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -376,6 +376,8 @@ pub struct EbpfVm<'a, C: ContextObject> { pub context_object_pointer: &'a mut C, /// Last return value of instruction_meter.get_remaining() pub previous_instruction_meter: u64, + /// Outstanding value to instruction_meter.consume() + pub due_insn_count: u64, /// CPU cycles accumulated by the stop watch pub stopwatch_numerator: u64, /// Number of times the stop watch was used @@ -422,6 +424,7 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { stack_pointer, context_object_pointer: context_object, previous_instruction_meter: 0, + due_insn_count: 0, stopwatch_numerator: 0, stopwatch_denominator: 0, registers: [0u64; 12], @@ -454,8 +457,9 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { 0 }; self.previous_instruction_meter = initial_insn_count; + self.due_insn_count = 0; self.program_result = ProgramResult::Ok(0); - let due_insn_count = if interpreted { + if interpreted { #[cfg(feature = "debugger")] let debug_port = self.debug_port.clone(); let mut interpreter = Interpreter::new(self, executable, self.registers); @@ -467,7 +471,6 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { } #[cfg(not(feature = "debugger"))] while interpreter.step() {} - interpreter.due_insn_count } else { #[cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] { @@ -480,9 +483,10 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { }; let instruction_meter_final = compiled_program.invoke(config, self, self.registers).max(0) as u64; - self.context_object_pointer + self.due_insn_count = self + .context_object_pointer .get_remaining() - .saturating_sub(instruction_meter_final) + .saturating_sub(instruction_meter_final); } #[cfg(not(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64")))] { @@ -490,7 +494,7 @@ impl<'a, C: ContextObject> EbpfVm<'a, C> { } }; let instruction_count = if config.enable_instruction_meter { - self.context_object_pointer.consume(due_insn_count); + self.context_object_pointer.consume(self.due_insn_count); initial_insn_count.saturating_sub(self.context_object_pointer.get_remaining()) } else { 0