From f337a6ac24c0acb0bdedc23c6f4013ca1386947e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 10 Apr 2023 15:44:45 +0200 Subject: [PATCH] Dissolves the wrapper VerifiedExecutable. (#458) Exposes TautologyVerifier to the public interface. --- benches/elf_loader.rs | 13 +++-- benches/jit_compile.rs | 15 +++--- benches/vm_execution.rs | 18 +++---- cli/src/main.rs | 17 +++---- examples/disassemble.rs | 3 +- examples/to_json.rs | 3 +- fuzz/fuzz_targets/dumb.rs | 13 ++--- fuzz/fuzz_targets/smart.rs | 13 ++--- fuzz/fuzz_targets/smart_jit_diff.rs | 17 +++---- fuzz/fuzz_targets/smarter_jit_diff.rs | 26 +++++----- src/assembler.rs | 5 +- src/elf.rs | 61 +++++++++++++++-------- src/interpreter.rs | 19 +++---- src/jit.rs | 22 ++++++--- src/static_analysis.rs | 7 +-- src/verifier.rs | 5 +- src/vm.rs | 66 ++++++------------------- src/x86.rs | 3 +- test_utils/src/lib.rs | 23 ++------- tests/misc.rs | 13 +++-- tests/ubpf_execution.rs | 43 ++++++---------- tests/ubpf_verifier.rs | 71 ++++++++++----------------- 22 files changed, 203 insertions(+), 273 deletions(-) diff --git a/benches/elf_loader.rs b/benches/elf_loader.rs index fa4481dec..34758bf0a 100644 --- a/benches/elf_loader.rs +++ b/benches/elf_loader.rs @@ -13,6 +13,7 @@ extern crate test_utils; use solana_rbpf::{ elf::Executable, syscalls::bpf_syscall_u64, + verifier::TautologyVerifier, vm::{BuiltInProgram, Config, TestContextObject}, }; use std::{fs::File, io::Read, sync::Arc}; @@ -32,7 +33,9 @@ fn bench_load_elf(bencher: &mut Bencher) { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); let loader = loader(); - bencher.iter(|| Executable::::from_elf(&elf, loader.clone()).unwrap()); + bencher.iter(|| { + Executable::::from_elf(&elf, loader.clone()).unwrap() + }); } #[bench] @@ -41,7 +44,9 @@ fn bench_load_elf_without_syscall(bencher: &mut Bencher) { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); let loader = loader(); - bencher.iter(|| Executable::::from_elf(&elf, loader.clone()).unwrap()); + bencher.iter(|| { + Executable::::from_elf(&elf, loader.clone()).unwrap() + }); } #[bench] @@ -50,5 +55,7 @@ fn bench_load_elf_with_syscall(bencher: &mut Bencher) { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); let loader = loader(); - bencher.iter(|| Executable::::from_elf(&elf, loader.clone()).unwrap()); + bencher.iter(|| { + Executable::::from_elf(&elf, loader.clone()).unwrap() + }); } diff --git a/benches/jit_compile.rs b/benches/jit_compile.rs index 8adf6d4c7..b8ef5bea1 100644 --- a/benches/jit_compile.rs +++ b/benches/jit_compile.rs @@ -11,25 +11,25 @@ extern crate test; use solana_rbpf::{ elf::Executable, - vm::{BuiltInProgram, Config, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier}, + vm::{BuiltInProgram, Config, TestContextObject}, }; use std::{fs::File, io::Read, sync::Arc}; use test::Bencher; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; #[bench] fn bench_init_vm(bencher: &mut Bencher) { let mut file = File::open("tests/elfs/pass_stack_reference.so").unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let executable = Executable::::from_elf( + let executable = Executable::::from_elf( &elf, Arc::new(BuiltInProgram::new_loader(Config::default())), ) .unwrap(); let verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); bencher.iter(|| { let mut context_object = TestContextObject::default(); create_vm!( @@ -50,13 +50,12 @@ fn bench_jit_compile(bencher: &mut Bencher) { let mut file = File::open("tests/elfs/pass_stack_reference.so").unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let executable = Executable::::from_elf( + let executable = Executable::::from_elf( &elf, Arc::new(BuiltInProgram::new_loader(Config::default())), ) .unwrap(); let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); bencher.iter(|| verified_executable.jit_compile().unwrap()); } diff --git a/benches/vm_execution.rs b/benches/vm_execution.rs index b9696986f..540525c64 100644 --- a/benches/vm_execution.rs +++ b/benches/vm_execution.rs @@ -13,25 +13,25 @@ use solana_rbpf::{ ebpf, elf::Executable, memory_region::MemoryRegion, - vm::{BuiltInProgram, Config, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier}, + vm::{BuiltInProgram, Config, TestContextObject}, }; use std::{fs::File, io::Read, sync::Arc}; use test::Bencher; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; #[bench] fn bench_init_interpreter_execution(bencher: &mut Bencher) { let mut file = File::open("tests/elfs/pass_stack_reference.so").unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let executable = Executable::::from_elf( + let executable = Executable::::from_elf( &elf, Arc::new(BuiltInProgram::new_loader(Config::default())), ) .unwrap(); let verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); let mut context_object = TestContextObject::default(); create_vm!( vm, @@ -54,14 +54,13 @@ fn bench_init_jit_execution(bencher: &mut Bencher) { let mut file = File::open("tests/elfs/pass_stack_reference.so").unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let executable = Executable::::from_elf( + let executable = Executable::::from_elf( &elf, Arc::new(BuiltInProgram::new_loader(Config::default())), ) .unwrap(); let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); verified_executable.jit_compile().unwrap(); let mut context_object = TestContextObject::default(); create_vm!( @@ -93,8 +92,7 @@ fn bench_jit_vs_interpreter( ) .unwrap(); let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); verified_executable.jit_compile().unwrap(); let mut context_object = TestContextObject::default(); let mem_region = MemoryRegion::new_writable(mem, ebpf::MM_INPUT_START); diff --git a/cli/src/main.rs b/cli/src/main.rs index d9fa6d373..74f030cce 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -6,8 +6,8 @@ use solana_rbpf::{ elf::Executable, memory_region::{MemoryMapping, MemoryRegion}, static_analysis::Analysis, - verifier::RequisiteVerifier, - vm::{BuiltInProgram, Config, DynamicAnalysis, EbpfVm, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier}, + vm::{BuiltInProgram, Config, DynamicAnalysis, EbpfVm, TestContextObject}, }; use std::{fs::File, io::Read, path::Path, sync::Arc}; @@ -108,16 +108,15 @@ fn main() { let mut file = File::open(Path::new(matches.value_of("elf").unwrap())).unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - Executable::::from_elf(&elf, loader) + Executable::::from_elf(&elf, loader) .map_err(|err| format!("Executable constructor failed: {err:?}")) } } .unwrap(); #[allow(unused_mut)] - let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + let verified_executable = + Executable::::verified(executable).unwrap(); let mut mem = match matches.value_of("input").unwrap().parse::() { Ok(allocate) => vec![0u8; allocate], @@ -139,7 +138,7 @@ fn main() { .parse::() .unwrap(), ); - let config = verified_executable.get_executable().get_config(); + let config = verified_executable.get_config(); let mut stack = AlignedMemory::<{ ebpf::HOST_ALIGN }>::zero_filled(config.stack_size()); let stack_len = stack.len(); let mut heap = AlignedMemory::<{ ebpf::HOST_ALIGN }>::zero_filled( @@ -150,7 +149,7 @@ fn main() { .unwrap(), ); let regions: Vec = vec![ - verified_executable.get_executable().get_ro_region(), + verified_executable.get_ro_region(), MemoryRegion::new_writable_gapped( stack.as_slice_mut(), ebpf::MM_STACK_START, @@ -178,7 +177,7 @@ fn main() { || matches.is_present("trace") || matches.is_present("profile") { - Some(Analysis::from_executable(verified_executable.get_executable()).unwrap()) + Some(Analysis::from_executable(&verified_executable).unwrap()) } else { None }; diff --git a/examples/disassemble.rs b/examples/disassemble.rs index a3024e30e..4e79b2161 100644 --- a/examples/disassemble.rs +++ b/examples/disassemble.rs @@ -8,6 +8,7 @@ extern crate solana_rbpf; use solana_rbpf::{ elf::Executable, static_analysis::Analysis, + verifier::TautologyVerifier, vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; use std::sync::Arc; @@ -31,7 +32,7 @@ fn main() { 0x00, 0x00, 0x00, 0x00, 0x00, ]; let loader = Arc::new(BuiltInProgram::default()); - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( program, loader, FunctionRegistry::default(), diff --git a/examples/to_json.rs b/examples/to_json.rs index 4ec836516..44748f077 100644 --- a/examples/to_json.rs +++ b/examples/to_json.rs @@ -14,6 +14,7 @@ extern crate solana_rbpf; use solana_rbpf::{ elf::Executable, static_analysis::Analysis, + verifier::TautologyVerifier, vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; use std::sync::Arc; @@ -27,7 +28,7 @@ use std::sync::Arc; // * Print integers as integers, and not as strings containing their hexadecimal representation // (just replace the relevant `format!()` calls by the commented values. fn to_json(program: &[u8]) -> String { - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( program, Arc::new(BuiltInProgram::default()), FunctionRegistry::default(), diff --git a/fuzz/fuzz_targets/dumb.rs b/fuzz/fuzz_targets/dumb.rs index 903fe3be5..9c3ad4ef7 100644 --- a/fuzz/fuzz_targets/dumb.rs +++ b/fuzz/fuzz_targets/dumb.rs @@ -8,10 +8,10 @@ use solana_rbpf::{ ebpf, elf::Executable, memory_region::MemoryRegion, - verifier::{RequisiteVerifier, Verifier}, - vm::{BuiltInProgram, FunctionRegistry, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier, Verifier}, + vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; use crate::common::ConfigTemplate; @@ -33,20 +33,17 @@ fuzz_target!(|data: DumbFuzzData| { return; } let mut mem = data.mem; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( &prog, std::sync::Arc::new(BuiltInProgram::new_loader(config)), function_registry, ) .unwrap(); - let verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); let mem_region = MemoryRegion::new_writable(&mut mem, ebpf::MM_INPUT_START); let mut context_object = TestContextObject::new(29); create_vm!( interp_vm, - &verified_executable, + &executable, &mut context_object, stack, heap, diff --git a/fuzz/fuzz_targets/smart.rs b/fuzz/fuzz_targets/smart.rs index 022507173..ef16afcbd 100644 --- a/fuzz/fuzz_targets/smart.rs +++ b/fuzz/fuzz_targets/smart.rs @@ -10,10 +10,10 @@ use solana_rbpf::{ elf::Executable, insn_builder::{Arch, IntoBytes}, memory_region::MemoryRegion, - verifier::{RequisiteVerifier, Verifier}, - vm::{BuiltInProgram, FunctionRegistry, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier, Verifier}, + vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; use crate::common::ConfigTemplate; @@ -37,20 +37,17 @@ fuzz_target!(|data: FuzzData| { return; } let mut mem = data.mem; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( prog.into_bytes(), std::sync::Arc::new(BuiltInProgram::new_loader(config)), function_registry, ) .unwrap(); - let verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); let mem_region = MemoryRegion::new_writable(&mut mem, ebpf::MM_INPUT_START); let mut context_object = TestContextObject::new(1 << 16); create_vm!( interp_vm, - &verified_executable, + &executable, &mut context_object, stack, heap, diff --git a/fuzz/fuzz_targets/smart_jit_diff.rs b/fuzz/fuzz_targets/smart_jit_diff.rs index 3b8b496a3..2a72c0942 100644 --- a/fuzz/fuzz_targets/smart_jit_diff.rs +++ b/fuzz/fuzz_targets/smart_jit_diff.rs @@ -8,10 +8,10 @@ use solana_rbpf::{ elf::Executable, insn_builder::{Arch, Instruction, IntoBytes}, memory_region::MemoryRegion, - verifier::{RequisiteVerifier, Verifier}, - vm::{BuiltInProgram, FunctionRegistry, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier, Verifier}, + vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; use crate::common::ConfigTemplate; @@ -45,21 +45,18 @@ fuzz_target!(|data: FuzzData| { } let mut interp_mem = data.mem.clone(); let mut jit_mem = data.mem; - let executable = Executable::::from_text_bytes( + let mut executable = Executable::::from_text_bytes( prog.into_bytes(), std::sync::Arc::new(BuiltInProgram::new_loader(config)), function_registry, ) .unwrap(); - let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); - if verified_executable.jit_compile().is_ok() { + if executable.jit_compile().is_ok() { let mut interp_context_object = TestContextObject::new(1 << 16); let interp_mem_region = MemoryRegion::new_writable(&mut interp_mem, ebpf::MM_INPUT_START); create_vm!( interp_vm, - &verified_executable, + &executable, &mut interp_context_object, interp_stack, interp_heap, @@ -71,7 +68,7 @@ fuzz_target!(|data: FuzzData| { let jit_mem_region = MemoryRegion::new_writable(&mut jit_mem, ebpf::MM_INPUT_START); create_vm!( jit_vm, - &verified_executable, + &executable, &mut jit_context_object, jit_stack, jit_heap, diff --git a/fuzz/fuzz_targets/smarter_jit_diff.rs b/fuzz/fuzz_targets/smarter_jit_diff.rs index da31356d4..370061df0 100644 --- a/fuzz/fuzz_targets/smarter_jit_diff.rs +++ b/fuzz/fuzz_targets/smarter_jit_diff.rs @@ -9,13 +9,12 @@ use solana_rbpf::{ insn_builder::IntoBytes, memory_region::MemoryRegion, static_analysis::Analysis, - verifier::{RequisiteVerifier, Verifier}, + verifier::{RequisiteVerifier, TautologyVerifier, Verifier}, vm::{ BuiltInProgram, ContextObject, FunctionRegistry, TestContextObject, - VerifiedExecutable, }, }; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; use crate::common::ConfigTemplate; @@ -29,8 +28,8 @@ struct FuzzData { mem: Vec, } -fn dump_insns(verified_executable: &VerifiedExecutable) { - let analysis = Analysis::from_executable(verified_executable.get_executable()).unwrap(); +fn dump_insns(verified_executable: &Executable) { + let analysis = Analysis::from_executable(verified_executable).unwrap(); eprint!("Using the following disassembly"); analysis.disassemble(&mut std::io::stderr().lock()).unwrap(); } @@ -45,21 +44,18 @@ fuzz_target!(|data: FuzzData| { } let mut interp_mem = data.mem.clone(); let mut jit_mem = data.mem; - let executable = Executable::::from_text_bytes( + let mut executable = Executable::::from_text_bytes( prog.into_bytes(), std::sync::Arc::new(BuiltInProgram::new_loader(config)), function_registry, ) .unwrap(); - let mut verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); - if verified_executable.jit_compile().is_ok() { + if executable.jit_compile().is_ok() { let mut interp_context_object = TestContextObject::new(1 << 16); let interp_mem_region = MemoryRegion::new_writable(&mut interp_mem, ebpf::MM_INPUT_START); create_vm!( interp_vm, - &verified_executable, + &executable, &mut interp_context_object, interp_stack, interp_heap, @@ -71,7 +67,7 @@ fuzz_target!(|data: FuzzData| { let jit_mem_region = MemoryRegion::new_writable(&mut jit_mem, ebpf::MM_INPUT_START); create_vm!( jit_vm, - &verified_executable, + &executable, &mut jit_context_object, jit_stack, jit_heap, @@ -90,20 +86,20 @@ fuzz_target!(|data: FuzzData| { return; } eprintln!("{:#?}", &data.prog); - dump_insns(&verified_executable); + dump_insns(&executable); panic!("Expected {}, but got {}", interp_res_str, jit_res_str); } if interp_res.is_ok() { // we know jit res must be ok if interp res is by this point if interp_context_object.remaining != jit_context_object.remaining { - dump_insns(&verified_executable); + dump_insns(&executable); panic!( "Expected {} insts remaining, but got {}", interp_context_object.remaining, jit_context_object.remaining ); } if interp_mem != jit_mem { - dump_insns(&verified_executable); + dump_insns(&executable); panic!( "Expected different memory. From interpreter: {:?}\nFrom JIT: {:?}", interp_mem, jit_mem diff --git a/src/assembler.rs b/src/assembler.rs index 02b439a1a..3a8448e87 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -19,6 +19,7 @@ use crate::{ }, ebpf::{self, Insn}, elf::{register_internal_function, Executable}, + verifier::TautologyVerifier, vm::{BuiltInProgram, ContextObject, FunctionRegistry}, }; use std::{collections::HashMap, sync::Arc}; @@ -216,7 +217,7 @@ fn insn(opc: u8, dst: i64, src: i64, off: i64, imm: i64) -> Result pub fn assemble( src: &str, loader: Arc>, -) -> Result, String> { +) -> Result, String> { fn resolve_label( insn_ptr: usize, labels: &HashMap<&str, usize>, @@ -352,6 +353,6 @@ pub fn assemble( .iter() .flat_map(|insn| insn.to_vec()) .collect::>(); - Executable::::from_text_bytes(&program, loader, function_registry) + Executable::::from_text_bytes(&program, loader, function_registry) .map_err(|err| format!("Executable constructor {err:?}")) } diff --git a/src/elf.rs b/src/elf.rs index 3fecbf5e5..a2ce330f1 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -20,7 +20,9 @@ use crate::{ ElfParser, ElfProgramHeader, ElfRelocation, ElfSectionHeader, ElfSymbol, GoblinParser, NewParser, }, + error::EbpfError, memory_region::MemoryRegion, + verifier::{TautologyVerifier, Verifier}, vm::{BuiltInProgram, Config, ContextObject, FunctionRegistry}, }; @@ -30,6 +32,7 @@ use byteorder::{ByteOrder, LittleEndian}; use std::{ collections::{btree_map::Entry, BTreeMap}, fmt::Debug, + marker::PhantomData, mem, ops::Range, str, @@ -265,7 +268,9 @@ pub(crate) enum Section { /// Elf loader/relocator #[derive(Debug, PartialEq)] -pub struct Executable { +pub struct Executable { + /// Verifier that verified this program + _verifier: PhantomData, /// Loaded and executable elf elf_bytes: AlignedMemory<{ HOST_ALIGN }>, /// Read-only section @@ -283,7 +288,7 @@ pub struct Executable { compiled_program: Option, } -impl Executable { +impl Executable { /// Get the configuration settings pub fn get_config(&self) -> &Config { self.loader.get_config() @@ -351,11 +356,23 @@ impl Executable { self.compiled_program.as_ref() } + /// Verify the executable + pub fn verified(executable: Executable) -> Result { + ::verify( + executable.get_text_bytes().1, + executable.get_config(), + executable.get_function_registry(), + )?; + Ok(unsafe { + std::mem::transmute::, Executable>(executable) + }) + } + /// JIT compile the executable #[cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] - pub fn jit_compile(executable: &mut Self) -> Result<(), crate::error::EbpfError> { - let jit = JitCompiler::::new(executable)?; - executable.compiled_program = Some(jit.compile()?); + pub fn jit_compile(&mut self) -> Result<(), crate::error::EbpfError> { + let jit = JitCompiler::::new(self)?; + self.compiled_program = Some(jit.compile()?); Ok(()) } @@ -383,6 +400,7 @@ impl Executable { 0 }; Ok(Self { + _verifier: PhantomData::default(), elf_bytes, ro_section: Section::Borrowed(0, 0..text_bytes.len()), text_section_info: SectionInfo { @@ -497,6 +515,7 @@ impl Executable { )?; Ok(Self { + _verifier: PhantomData::default(), elf_bytes, ro_section, text_section_info, @@ -1207,7 +1226,7 @@ mod test { use rand::{distributions::Uniform, Rng}; use std::{fs::File, io::Read}; use test_utils::assert_error; - type ElfExecutable = Executable; + type ElfExecutable = Executable; fn loader() -> Arc> { let mut loader = BuiltInProgram::new_loader(Config::default()); @@ -1327,7 +1346,7 @@ mod test { .expect("failed to read elf file"); let elf = ElfExecutable::load(&elf_bytes, loader.clone()).expect("validation failed"); let parsed_elf = NewParser::parse(&elf_bytes).unwrap(); - let executable: &Executable = &elf; + let executable: &Executable = &elf; assert_eq!(0, executable.get_entrypoint_instruction_offset()); let write_header = |header: Elf64Ehdr| unsafe { @@ -1342,34 +1361,34 @@ mod test { header.e_entry += 8; let elf_bytes = write_header(header.clone()); let elf = ElfExecutable::load(&elf_bytes, loader.clone()).expect("validation failed"); - let executable: &Executable = &elf; + let executable: &Executable = &elf; assert_eq!(1, executable.get_entrypoint_instruction_offset()); header.e_entry = 1; let elf_bytes = write_header(header.clone()); - assert_eq!( - Err(ElfError::EntrypointOutOfBounds), - ElfExecutable::load(&elf_bytes, loader.clone()) - ); + assert!(matches!( + ElfExecutable::load(&elf_bytes, loader.clone()), + Err(ElfError::EntrypointOutOfBounds) + )); header.e_entry = u64::MAX; let elf_bytes = write_header(header.clone()); - assert_eq!( - Err(ElfError::EntrypointOutOfBounds), - ElfExecutable::load(&elf_bytes, loader.clone()) - ); + assert!(matches!( + ElfExecutable::load(&elf_bytes, loader.clone()), + Err(ElfError::EntrypointOutOfBounds) + )); header.e_entry = initial_e_entry + ebpf::INSN_SIZE as u64 + 1; let elf_bytes = write_header(header.clone()); - assert_eq!( - Err(ElfError::InvalidEntrypoint), - ElfExecutable::load(&elf_bytes, loader.clone()) - ); + assert!(matches!( + ElfExecutable::load(&elf_bytes, loader.clone()), + Err(ElfError::InvalidEntrypoint) + )); header.e_entry = initial_e_entry; let elf_bytes = write_header(header); let elf = ElfExecutable::load(&elf_bytes, loader).expect("validation failed"); - let executable: &Executable = &elf; + let executable: &Executable = &elf; assert_eq!(0, executable.get_entrypoint_instruction_offset()); } diff --git a/src/interpreter.rs b/src/interpreter.rs index b110af116..6f21ba890 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -85,8 +85,7 @@ pub struct Interpreter<'a, 'b, V: Verifier, C: ContextObject> { impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { /// Creates a new interpreter state pub fn new(vm: &'a mut EbpfVm<'b, V, C>, registers: [u64; 12]) -> Self { - let executable = vm.verified_executable.get_executable(); - let (program_vm_addr, program) = executable.get_text_bytes(); + let (program_vm_addr, program) = vm.executable.get_text_bytes(); Self { vm, program, @@ -123,12 +122,7 @@ impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { /// Translate between the virtual machines' pc value and the pc value used by the debugger #[cfg(feature = "debugger")] pub fn get_dbg_pc(&self) -> u64 { - ((self.pc * ebpf::INSN_SIZE) as u64) - + self - .vm - .verified_executable - .get_executable() - .get_text_section_offset() + ((self.pc * ebpf::INSN_SIZE) as u64) + self.vm.executable.get_text_section_offset() } fn push_frame(&mut self, config: &Config) -> bool { @@ -166,8 +160,7 @@ impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { /// Returns false if the program terminated or threw an error. #[rustfmt::skip] pub fn step(&mut self) -> bool { - let executable = self.vm.verified_executable.get_executable(); - let config = &executable.get_config(); + let config = &self.vm.executable.get_config(); let mut instruction_width = 1; self.due_insn_count += 1; @@ -427,7 +420,7 @@ impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { if !self.check_pc(pc) { return false; } - if config.static_syscalls && executable.lookup_internal_function(self.pc as u32).is_none() { + if config.static_syscalls && self.vm.executable.lookup_internal_function(self.pc as u32).is_none() { self.due_insn_count += 1; throw_error!(self, EbpfError::UnsupportedInstruction(self.pc + ebpf::ELF_INSN_DUMP_OFFSET)); } @@ -444,7 +437,7 @@ impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { }; if external { - if let Some((_function_name, function)) = executable.get_loader().lookup_function(insn.imm as u32) { + if let Some((_function_name, function)) = self.vm.executable.get_loader().lookup_function(insn.imm as u32) { resolved = true; if config.enable_instruction_meter { @@ -472,7 +465,7 @@ impl<'a, 'b, V: Verifier, C: ContextObject> Interpreter<'a, 'b, V, C> { } if internal && !resolved { - if let Some(target_pc) = executable.lookup_internal_function(insn.imm as u32) { + if let Some(target_pc) = self.vm.executable.lookup_internal_function(insn.imm as u32) { resolved = true; // make BPF to BPF call diff --git a/src/jit.rs b/src/jit.rs index c06866cba..22983b83e 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -21,6 +21,7 @@ use crate::{ allocate_pages, free_pages, get_system_page_size, protect_pages, round_to_page_size, }, memory_region::{AccessType, MemoryMapping}, + verifier::Verifier, vm::{Config, ContextObject, ProgramResult, RuntimeEnvironment}, x86::*, }; @@ -303,7 +304,7 @@ enum RuntimeEnvironmentSlot { and undo again can be anything, so we just set it to zero. */ -pub struct JitCompiler<'a, C: ContextObject> { +pub struct JitCompiler<'a, V: Verifier, C: ContextObject> { result: JitProgram, text_section_jumps: Vec, anchors: [*const u8; ANCHOR_COUNT], @@ -311,7 +312,7 @@ pub struct JitCompiler<'a, C: ContextObject> { pc: usize, last_instruction_meter_validation_pc: usize, next_noop_insertion: u32, - executable: &'a Executable, + executable: &'a Executable, program: &'a [u8], program_vm_addr: u64, config: &'a Config, @@ -320,9 +321,9 @@ pub struct JitCompiler<'a, C: ContextObject> { } #[rustfmt::skip] -impl<'a, C: ContextObject> JitCompiler<'a, C> { +impl<'a, V: Verifier, C: ContextObject> JitCompiler<'a, V, C> { /// Constructs a new compiler and allocates memory for the compilation output - pub fn new(executable: &'a Executable) -> Result { + pub fn new(executable: &'a Executable) -> Result { let config = executable.get_config(); let (program_vm_addr, program) = executable.get_text_bytes(); @@ -1533,6 +1534,7 @@ mod tests { use super::*; use crate::{ syscalls, + verifier::TautologyVerifier, vm::{BuiltInProgram, FunctionRegistry, TestContextObject}, }; use byteorder::{ByteOrder, LittleEndian}; @@ -1578,7 +1580,9 @@ mod tests { check_slot!(env, memory_mapping, MemoryMapping); } - fn create_mockup_executable(program: &[u8]) -> Executable { + fn create_mockup_executable( + program: &[u8], + ) -> Executable { let mut loader = BuiltInProgram::new_loader(Config { noop_instruction_rate: 0, ..Config::default() @@ -1588,7 +1592,7 @@ mod tests { .unwrap(); let mut function_registry = FunctionRegistry::default(); function_registry.insert(8, (8, "function_foo".to_string())); - Executable::::from_text_bytes( + Executable::::from_text_bytes( program, Arc::new(loader), function_registry, @@ -1604,7 +1608,8 @@ mod tests { let empty_program_machine_code_length = { prog[0] = ebpf::EXIT; let mut executable = create_mockup_executable(&prog[0..ebpf::INSN_SIZE]); - Executable::::jit_compile(&mut executable).unwrap(); + Executable::::jit_compile(&mut executable) + .unwrap(); executable .get_compiled_program() .unwrap() @@ -1631,7 +1636,8 @@ mod tests { LittleEndian::write_u32(&mut prog[pc * ebpf::INSN_SIZE + 4..], immediate); } let mut executable = create_mockup_executable(&prog); - let result = Executable::::jit_compile(&mut executable); + let result = + Executable::::jit_compile(&mut executable); if result.is_err() { assert!(matches!( result.unwrap_err(), diff --git a/src/static_analysis.rs b/src/static_analysis.rs index 2cd862c08..d713f3479 100644 --- a/src/static_analysis.rs +++ b/src/static_analysis.rs @@ -6,6 +6,7 @@ use crate::{ ebpf, elf::{self, Executable}, error::EbpfError, + verifier::{TautologyVerifier, Verifier}, vm::{ContextObject, DynamicAnalysis, TestContextObject}, }; use rustc_demangle::demangle; @@ -126,7 +127,7 @@ impl Default for CfgNode { /// Result of the executable analysis pub struct Analysis<'a> { /// The program which is analyzed - executable: &'a Executable, + executable: &'a Executable, /// Plain list of instructions as they occur in the executable pub instructions: Vec, /// Functions in the executable @@ -147,8 +148,8 @@ pub struct Analysis<'a> { impl<'a> Analysis<'a> { /// Analyze an executable statically - pub fn from_executable( - executable: &'a Executable, + pub fn from_executable( + executable: &'a Executable, ) -> Result { let (_program_vm_addr, program) = executable.get_text_bytes(); let mut functions = BTreeMap::new(); diff --git a/src/verifier.rs b/src/verifier.rs index f40b1d863..685089af0 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -383,8 +383,9 @@ impl Verifier for RequisiteVerifier { } } -// Warning: For test purposes only -pub(crate) struct TautologyVerifier {} +/// Passes all inputs. Used to mark executables as unverified. +#[derive(Debug)] +pub struct TautologyVerifier {} impl Verifier for TautologyVerifier { fn verify( _prog: &[u8], diff --git a/src/vm.rs b/src/vm.rs index d05af8dc4..fe58e0fac 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -19,13 +19,12 @@ use crate::{ interpreter::Interpreter, memory_region::MemoryMapping, static_analysis::{Analysis, TraceLogEntry}, - verifier::Verifier, + verifier::{TautologyVerifier, Verifier}, }; use rand::Rng; use std::{ collections::{BTreeMap, HashMap}, fmt::Debug, - marker::PhantomData, mem, sync::Arc, }; @@ -281,7 +280,7 @@ impl Default for Config { } /// Static constructors for Executable -impl Executable { +impl Executable { /// Creates an executable from an ELF file pub fn from_elf(elf_bytes: &[u8], loader: Arc>) -> Result { let executable = Executable::load(elf_bytes, loader)?; @@ -298,40 +297,6 @@ impl Executable { } } -/// Verified executable -#[derive(Debug, PartialEq)] -#[repr(transparent)] -pub struct VerifiedExecutable { - executable: Executable, - _verifier: PhantomData, -} - -impl VerifiedExecutable { - /// Verify an executable - pub fn from_executable(executable: Executable) -> Result { - ::verify( - executable.get_text_bytes().1, - executable.get_config(), - executable.get_function_registry(), - )?; - Ok(VerifiedExecutable { - executable, - _verifier: PhantomData, - }) - } - - /// JIT compile the executable - #[cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] - pub fn jit_compile(&mut self) -> Result<(), EbpfError> { - Executable::::jit_compile(&mut self.executable) - } - - /// Get a reference to the underlying executable - pub fn get_executable(&self) -> &Executable { - &self.executable - } -} - /// Runtime context pub trait ContextObject { /// Called for every instruction executed when tracing is enabled @@ -476,8 +441,8 @@ pub struct RuntimeEnvironment<'a, C: ContextObject> { /// ebpf, /// elf::Executable, /// memory_region::{MemoryMapping, MemoryRegion}, -/// verifier::RequisiteVerifier, -/// vm::{BuiltInProgram, Config, EbpfVm, FunctionRegistry, TestContextObject, VerifiedExecutable}, +/// verifier::{TautologyVerifier, RequisiteVerifier}, +/// vm::{BuiltInProgram, Config, EbpfVm, FunctionRegistry, TestContextObject}, /// }; /// /// let prog = &[ @@ -489,17 +454,17 @@ pub struct RuntimeEnvironment<'a, C: ContextObject> { /// /// let loader = std::sync::Arc::new(BuiltInProgram::new_loader(Config::default())); /// let function_registry = FunctionRegistry::default(); -/// let mut executable = Executable::::from_text_bytes(prog, loader, function_registry).unwrap(); -/// let verified_executable = VerifiedExecutable::::from_executable(executable).unwrap(); +/// let mut executable = Executable::::from_text_bytes(prog, loader, function_registry).unwrap(); +/// let verified_executable = Executable::::verified(executable).unwrap(); /// let mut context_object = TestContextObject::new(1); -/// let config = verified_executable.get_executable().get_config(); +/// let config = verified_executable.get_config(); /// /// let mut stack = AlignedMemory::<{ebpf::HOST_ALIGN}>::zero_filled(config.stack_size()); /// let stack_len = stack.len(); /// let mut heap = AlignedMemory::<{ebpf::HOST_ALIGN}>::with_capacity(0); /// /// let regions: Vec = vec![ -/// verified_executable.get_executable().get_ro_region(), +/// verified_executable.get_ro_region(), /// MemoryRegion::new_writable_gapped( /// stack.as_slice_mut(), /// ebpf::MM_STACK_START, @@ -522,7 +487,7 @@ pub struct RuntimeEnvironment<'a, C: ContextObject> { /// assert_eq!(result.unwrap(), 0); /// ``` pub struct EbpfVm<'a, V: Verifier, C: ContextObject> { - pub(crate) verified_executable: &'a VerifiedExecutable, + pub(crate) executable: &'a Executable, /// TCP port for the debugger interface #[cfg(feature = "debugger")] pub debug_port: Option, @@ -533,12 +498,11 @@ pub struct EbpfVm<'a, V: Verifier, C: ContextObject> { impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> { /// Creates a new virtual machine instance. pub fn new( - verified_executable: &'a VerifiedExecutable, + executable: &'a Executable, context_object: &'a mut C, memory_mapping: MemoryMapping<'a>, stack_len: usize, ) -> EbpfVm<'a, V, C> { - let executable = verified_executable.get_executable(); let config = executable.get_config(); let stack_pointer = ebpf::MM_STACK_START.saturating_add(if config.dynamic_stack_frames { // the stack is fully descending, frames start as empty and change size anytime r11 is modified @@ -548,7 +512,7 @@ impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> { config.stack_frame_size } as u64); EbpfVm { - verified_executable, + executable, #[cfg(feature = "debugger")] debug_port: None, env: RuntimeEnvironment { @@ -570,13 +534,12 @@ impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> { /// /// If interpreted = `false` then the JIT compiled executable is used. pub fn execute_program(&mut self, interpreted: bool) -> (u64, ProgramResult) { - let executable = self.verified_executable.get_executable(); let mut registers = [0u64; 12]; // R1 points to beginning of input memory, R10 to the stack of the first frame, R11 is the pc (hidden) registers[1] = ebpf::MM_INPUT_START; registers[ebpf::FRAME_PTR_REG] = self.env.stack_pointer; - registers[11] = executable.get_entrypoint_instruction_offset() as u64; - let config = executable.get_config(); + registers[11] = self.executable.get_entrypoint_instruction_offset() as u64; + let config = self.executable.get_config(); let initial_insn_count = if config.enable_instruction_meter { self.env.context_object_pointer.get_remaining() } else { @@ -600,7 +563,8 @@ impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> { } else { #[cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] { - let compiled_program = match executable + let compiled_program = match self + .executable .get_compiled_program() .ok_or_else(|| Box::new(EbpfError::JitNotCompiled)) { diff --git a/src/x86.rs b/src/x86.rs index 22a798d4f..1aeb01093 100644 --- a/src/x86.rs +++ b/src/x86.rs @@ -1,6 +1,7 @@ #![allow(clippy::integer_arithmetic)] use crate::{ jit::{JitCompiler, OperandSize}, + verifier::Verifier, vm::ContextObject, }; @@ -102,7 +103,7 @@ impl X86Instruction { }; #[inline] - pub fn emit(&self, jit: &mut JitCompiler) { + pub fn emit(&self, jit: &mut JitCompiler) { debug_assert!(!matches!(self.size, OperandSize::S0)); let mut rex = X86Rex { w: matches!(self.size, OperandSize::S64), diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 748ff4e60..d9f449d4c 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs @@ -14,6 +14,7 @@ use solana_rbpf::{ elf::Executable, error::EbpfError, memory_region::{MemoryCowCallback, MemoryMapping, MemoryRegion}, + verifier::Verifier, vm::ContextObject, }; @@ -158,19 +159,8 @@ pub const TCP_SACK_NOMATCH: [u8; 66] = [ 0x9e, 0x27, // ]; -pub struct TautologyVerifier {} -impl solana_rbpf::verifier::Verifier for TautologyVerifier { - fn verify( - _prog: &[u8], - _config: &solana_rbpf::vm::Config, - _function_registry: &solana_rbpf::vm::FunctionRegistry, - ) -> std::result::Result<(), solana_rbpf::verifier::VerifierError> { - Ok(()) - } -} - -pub fn create_memory_mapping<'a, C: ContextObject>( - executable: &'a Executable, +pub fn create_memory_mapping<'a, V: Verifier, C: ContextObject>( + executable: &'a Executable, stack: &'a mut AlignedMemory<{ HOST_ALIGN }>, heap: &'a mut AlignedMemory<{ HOST_ALIGN }>, additional_regions: Vec, @@ -205,15 +195,12 @@ pub fn create_memory_mapping<'a, C: ContextObject>( macro_rules! create_vm { ($vm_name:ident, $verified_executable:expr, $context_object:expr, $stack:ident, $heap:ident, $additional_regions:expr, $cow_cb:expr) => { let mut $stack = solana_rbpf::aligned_memory::AlignedMemory::zero_filled( - $verified_executable - .get_executable() - .get_config() - .stack_size(), + $verified_executable.get_config().stack_size(), ); let mut $heap = solana_rbpf::aligned_memory::AlignedMemory::with_capacity(0); let stack_len = $stack.len(); let memory_mapping = test_utils::create_memory_mapping( - $verified_executable.get_executable(), + $verified_executable, &mut $stack, &mut $heap, $additional_regions, diff --git a/tests/misc.rs b/tests/misc.rs index 551cf8f22..677276de2 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -26,8 +26,8 @@ use solana_rbpf::{ elf::Executable, fuzz::fuzz, syscalls, - verifier::RequisiteVerifier, - vm::{BuiltInProgram, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier}, + vm::{BuiltInProgram, TestContextObject}, }; use std::{fs::File, io::Read, sync::Arc}; use test_utils::create_vm; @@ -122,12 +122,11 @@ fn test_fuzz_execute() { 0..elf.len(), 0..255, |bytes: &mut [u8]| { - if let Ok(executable) = Executable::::from_elf(bytes, loader.clone()) + if let Ok(executable) = + Executable::::from_elf(bytes, loader.clone()) { - if let Ok(verified_executable) = VerifiedExecutable::< - RequisiteVerifier, - TestContextObject, - >::from_executable(executable) + if let Ok(verified_executable) = + Executable::::verified(executable) { let mut context_object = TestContextObject::new(1_000_000); create_vm!( diff --git a/tests/ubpf_execution.rs b/tests/ubpf_execution.rs index e554e273b..192ed11a3 100644 --- a/tests/ubpf_execution.rs +++ b/tests/ubpf_execution.rs @@ -21,11 +21,11 @@ use solana_rbpf::{ elf::Executable, error::EbpfError, memory_region::{AccessType, MemoryMapping, MemoryRegion}, + static_analysis::Analysis, syscalls, - verifier::RequisiteVerifier, + verifier::{RequisiteVerifier, TautologyVerifier}, vm::{ BuiltInProgram, Config, ContextObject, FunctionRegistry, ProgramResult, TestContextObject, - VerifiedExecutable, }, }; use std::{fs::File, io::Read, sync::Arc}; @@ -51,7 +51,7 @@ macro_rules! test_interpreter_and_jit { } #[allow(unused_mut)] let mut verified_executable = - VerifiedExecutable::::from_executable($executable).unwrap(); + Executable::::verified($executable).unwrap(); let (instruction_count_interpreter, _tracer_interpreter) = { let mut mem = $mem; let mem_region = MemoryRegion::new_writable(&mut mem, ebpf::MM_INPUT_START); @@ -100,10 +100,7 @@ macro_rules! test_interpreter_and_jit { let tracer_jit = &vm.env.context_object_pointer; assert_eq!(format!("{:?}", result), expected_result); if !TestContextObject::compare_trace_log(&_tracer_interpreter, tracer_jit) { - let analysis = solana_rbpf::static_analysis::Analysis::from_executable( - verified_executable.get_executable(), - ) - .unwrap(); + let analysis = Analysis::from_executable(&verified_executable).unwrap(); let stdout = std::io::stdout(); analysis .disassemble_trace_log( @@ -123,11 +120,7 @@ macro_rules! test_interpreter_and_jit { } } } - if verified_executable - .get_executable() - .get_config() - .enable_instruction_meter - { + if verified_executable.get_config().enable_instruction_meter { assert_eq!(instruction_count_interpreter, expected_instruction_count); } }; @@ -166,7 +159,7 @@ macro_rules! test_interpreter_and_jit_elf { let mut loader = BuiltInProgram::new_loader($config); $(test_interpreter_and_jit!(register, loader, $location => $syscall_function);)* let loader = Arc::new(loader); - let mut executable = Executable::::from_elf(&elf, loader).unwrap(); + let mut executable = Executable::::from_elf(&elf, loader).unwrap(); test_interpreter_and_jit!(executable, $mem, $context_object, $expected_result); } }; @@ -2579,7 +2572,7 @@ fn test_err_mem_access_out_of_bound() { LittleEndian::write_u32(&mut prog[4..], address as u32); LittleEndian::write_u32(&mut prog[12..], (address >> 32) as u32); #[allow(unused_mut)] - let mut executable = Executable::::from_text_bytes( + let mut executable = Executable::::from_text_bytes( &prog, loader.clone(), FunctionRegistry::default(), @@ -3442,7 +3435,7 @@ fn test_err_unresolved_elf() { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); assert_error!( - Executable::::from_elf(&elf, Arc::new(loader)), + Executable::::from_elf(&elf, Arc::new(loader)), "UnresolvedSymbol(\"log_64\", 67, 304)" ); } @@ -3822,7 +3815,7 @@ fn test_struct_func_pointer() { fn execute_generated_program(prog: &[u8]) -> bool { let max_instruction_count = 1024; let mem_size = 1024 * 1024; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( prog, Arc::new(BuiltInProgram::new_loader(Config { enable_instruction_tracing: true, @@ -3835,10 +3828,8 @@ fn execute_generated_program(prog: &[u8]) -> bool { } else { return false; }; - let verified_executable = VerifiedExecutable::< - solana_rbpf::verifier::RequisiteVerifier, - TestContextObject, - >::from_executable(executable); + let verified_executable = + Executable::::verified(executable); let mut verified_executable = if let Ok(verified_executable) = verified_executable { verified_executable } else { @@ -3885,10 +3876,8 @@ fn execute_generated_program(prog: &[u8]) -> bool { if format!("{result_interpreter:?}") != format!("{result_jit:?}") || !TestContextObject::compare_trace_log(&tracer_interpreter, tracer_jit) { - let analysis = solana_rbpf::static_analysis::Analysis::from_executable( - verified_executable.get_executable(), - ) - .unwrap(); + let analysis = + solana_rbpf::static_analysis::Analysis::from_executable(&verified_executable).unwrap(); println!("result_interpreter={result_interpreter:?}"); println!("result_jit={result_jit:?}"); let stdout = std::io::stdout(); @@ -3900,11 +3889,7 @@ fn execute_generated_program(prog: &[u8]) -> bool { .unwrap(); panic!(); } - if verified_executable - .get_executable() - .get_config() - .enable_instruction_meter - { + if verified_executable.get_config().enable_instruction_meter { assert_eq!(instruction_count_interpreter, instruction_count_jit); } true diff --git a/tests/ubpf_verifier.rs b/tests/ubpf_verifier.rs index 30e5a17f6..7b99df7fc 100644 --- a/tests/ubpf_verifier.rs +++ b/tests/ubpf_verifier.rs @@ -26,11 +26,11 @@ use solana_rbpf::{ assembler::assemble, ebpf, elf::Executable, - verifier::{RequisiteVerifier, Verifier, VerifierError}, - vm::{BuiltInProgram, Config, FunctionRegistry, TestContextObject, VerifiedExecutable}, + verifier::{RequisiteVerifier, TautologyVerifier, Verifier, VerifierError}, + vm::{BuiltInProgram, Config, FunctionRegistry, TestContextObject}, }; use std::sync::Arc; -use test_utils::{create_vm, TautologyVerifier}; +use test_utils::create_vm; use thiserror::Error; /// Error definitions @@ -61,8 +61,7 @@ fn test_verifier_success() { ) .unwrap(); let verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); create_vm!( _vm, &verified_executable, @@ -85,8 +84,7 @@ fn test_verifier_fail() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -101,8 +99,7 @@ fn test_verifier_err_div_by_zero_imm() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -113,15 +110,14 @@ fn test_verifier_err_endian_size() { 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( prog, Arc::new(BuiltInProgram::new_loader(Config::default())), FunctionRegistry::default(), ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -132,15 +128,14 @@ fn test_verifier_err_incomplete_lddw() { 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( prog, Arc::new(BuiltInProgram::new_loader(Config::default())), FunctionRegistry::default(), ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -158,9 +153,8 @@ fn test_verifier_err_invalid_reg_dst() { })), ) .unwrap(); - let result = - VerifiedExecutable::::from_executable(executable) - .map_err(|err| format!("Executable constructor {err:?}")); + let result = Executable::::verified(executable) + .map_err(|err| format!("Executable constructor {err:?}")); assert_eq!( result.unwrap_err(), @@ -184,9 +178,8 @@ fn test_verifier_err_invalid_reg_src() { })), ) .unwrap(); - let result = - VerifiedExecutable::::from_executable(executable) - .map_err(|err| format!("Executable constructor {err:?}")); + let result = Executable::::verified(executable) + .map_err(|err| format!("Executable constructor {err:?}")); assert_eq!( result.unwrap_err(), @@ -209,8 +202,7 @@ fn test_verifier_resize_stack_ptr_success() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -225,8 +217,7 @@ fn test_verifier_err_jmp_lddw() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -241,8 +232,7 @@ fn test_verifier_err_call_lddw() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -257,8 +247,7 @@ fn test_verifier_err_function_fallthrough() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -272,8 +261,7 @@ fn test_verifier_err_jmp_out() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -287,8 +275,7 @@ fn test_verifier_err_jmp_out_start() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -298,15 +285,14 @@ fn test_verifier_err_unknown_opcode() { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]; - let executable = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( prog, Arc::new(BuiltInProgram::new_loader(Config::default())), FunctionRegistry::default(), ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -320,8 +306,7 @@ fn test_verifier_err_write_r10() { ) .unwrap(); let _verified_executable = - VerifiedExecutable::::from_executable(executable) - .unwrap(); + Executable::::verified(executable).unwrap(); } #[test] @@ -357,9 +342,8 @@ fn test_verifier_err_all_shift_overflows() { Arc::new(BuiltInProgram::new_loader(Config::default())), ) .unwrap(); - let result = - VerifiedExecutable::::from_executable(executable) - .map_err(|err| format!("Executable constructor {err:?}")); + let result = Executable::::verified(executable) + .map_err(|err| format!("Executable constructor {err:?}")); match expected { Ok(()) => assert!(result.is_ok()), Err(overflow_msg) => match result { @@ -393,10 +377,7 @@ fn test_sdiv_disabled() { })), ) .unwrap(); - let result = - VerifiedExecutable::::from_executable( - executable, - ) + let result = Executable::::verified(executable) .map_err(|err| format!("Executable constructor {err:?}")); if enable_sdiv { assert!(result.is_ok());