From 7064f2f9ff8bbb49bfc16dd57b8ec762841846c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 4 Sep 2024 08:41:48 +0200 Subject: [PATCH 1/3] Uses the Uniform distribution type from rand for noop insertion instead of gen_range(). --- src/jit.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/jit.rs b/src/jit.rs index baba2b40..73c2a44e 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -16,7 +16,11 @@ use rand::{thread_rng, Rng}; #[cfg(feature = "shuttle-test")] use shuttle::rand::{thread_rng, Rng}; -use rand::{rngs::SmallRng, SeedableRng}; +use rand::{ + distributions::{Distribution, Uniform}, + rngs::SmallRng, + SeedableRng, +}; use std::{fmt::Debug, mem, ptr}; use crate::{ @@ -321,6 +325,7 @@ pub struct JitCompiler<'a, C: ContextObject> { pc: usize, last_instruction_meter_validation_pc: usize, next_noop_insertion: u32, + noop_range: Uniform, runtime_environment_key: i32, diversification_rng: SmallRng, stopwatch_is_active: bool, @@ -372,6 +377,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { pc: 0, last_instruction_meter_validation_pc: 0, next_noop_insertion: if config.noop_instruction_rate == 0 { u32::MAX } else { diversification_rng.gen_range(0..config.noop_instruction_rate * 2) }, + noop_range: Uniform::new_inclusive(0, config.noop_instruction_rate * 2), runtime_environment_key, diversification_rng, stopwatch_is_active: false, @@ -786,7 +792,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { pub fn emit_ins(&mut self, instruction: X86Instruction) { instruction.emit(self); if self.next_noop_insertion == 0 { - self.next_noop_insertion = self.diversification_rng.gen_range(0..self.config.noop_instruction_rate * 2); + self.next_noop_insertion = self.noop_range.sample(&mut self.diversification_rng); // X86Instruction::noop().emit(self)?; self.emit::(0x90); } else { From 322e9cdff61522c8f1ecfb78ab14567d4ecbc566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 4 Sep 2024 08:47:18 +0200 Subject: [PATCH 2/3] Makes the ExhaustedTextSegment check more conservative. --- src/jit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jit.rs b/src/jit.rs index 73c2a44e..ee6e9094 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -399,7 +399,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { self.emit_subroutines(); while self.pc * ebpf::INSN_SIZE < self.program.len() { - if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION > self.result.text_section.len() { + if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION * 2 >= self.result.text_section.len() { return Err(EbpfError::ExhaustedTextSegment(self.pc)); } let mut insn = ebpf::get_insn_unchecked(self.program, self.pc); @@ -729,7 +729,7 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { } // Bumper in case there was no final exit - if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION > self.result.text_section.len() { + if self.offset_in_text_section + MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION * 2 >= self.result.text_section.len() { return Err(EbpfError::ExhaustedTextSegment(self.pc)); } self.emit_validate_and_profile_instruction_count(true, Some(self.pc + 2)); From ef1fe8dfa801ae8cd409aa8c3852ffa01f623a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 4 Sep 2024 10:56:07 +0200 Subject: [PATCH 3/3] Makes cargo fmt happy. --- src/syscalls.rs | 6 ++++-- src/verifier.rs | 13 +------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/syscalls.rs b/src/syscalls.rs index c597d9b2..a8d398db 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -79,8 +79,10 @@ declare_builtin_function!( ); declare_builtin_function!( - /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in - /// section 3) for `memfrob`. The memory is directly modified, and the syscall returns 0 in all + /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. + /// + /// See the GNU manual page (in section 3) for `memfrob`. + /// The memory is directly modified, and the syscall returns 0 in all /// cases. Arguments 3 to 5 are unused. SyscallMemFrob, fn rust( diff --git a/src/verifier.rs b/src/verifier.rs index 05bef6ff..c4f774ba 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -10,18 +10,7 @@ // the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -//! This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is -//! interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside -//! Linux kernel. There is no verification regarding the program flow control (should be a Direct -//! Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types -//! to the registers and is much stricter). -//! -//! On the other hand, rbpf is not expected to run in kernel space. -//! -//! Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL -//! license, so we cannot copy it). -//! -//! Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all. +//! Verifies that the bytecode is valid for the given config. use crate::{ ebpf,