diff --git a/benches/elf_loader.rs b/benches/elf_loader.rs index 323be403..2a05da9b 100644 --- a/benches/elf_loader.rs +++ b/benches/elf_loader.rs @@ -12,7 +12,7 @@ extern crate test_utils; use solana_rbpf::{ elf::Executable, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry}, syscalls, vm::{Config, TestContextObject}, }; @@ -27,6 +27,7 @@ fn loader() -> Arc> { Arc::new(BuiltinProgram::new_loader( Config::default(), function_registry, + SyscallRegistry::default(), )) } diff --git a/benches/vm_execution.rs b/benches/vm_execution.rs index 4404c927..a753b863 100644 --- a/benches/vm_execution.rs +++ b/benches/vm_execution.rs @@ -13,7 +13,7 @@ extern crate test; use solana_rbpf::{ ebpf, memory_region::MemoryRegion, - program::{FunctionRegistry, SBPFVersion}, + program::{FunctionRegistry, SBPFVersion, SyscallRegistry}, vm::Config, }; use solana_rbpf::{ @@ -88,6 +88,7 @@ fn bench_jit_vs_interpreter( Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); diff --git a/cli/src/main.rs b/cli/src/main.rs index cded744a..ea9a497a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -5,7 +5,7 @@ use solana_rbpf::{ ebpf, elf::Executable, memory_region::{MemoryMapping, MemoryRegion}, - program::{BuiltinProgram, FunctionRegistry}, + program::{BuiltinProgram, FunctionRegistry, SyscallRegistry}, static_analysis::Analysis, verifier::RequisiteVerifier, vm::{Config, DynamicAnalysis, EbpfVm, TestContextObject}, @@ -101,6 +101,7 @@ fn main() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )); #[allow(unused_mut)] let mut executable = match matches.value_of("assembler") { diff --git a/fuzz/fuzz_targets/dumb.rs b/fuzz/fuzz_targets/dumb.rs index c1b1743d..c91799e5 100644 --- a/fuzz/fuzz_targets/dumb.rs +++ b/fuzz/fuzz_targets/dumb.rs @@ -8,7 +8,7 @@ use solana_rbpf::{ ebpf, elf::Executable, memory_region::MemoryRegion, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion}, verifier::{RequisiteVerifier, Verifier}, vm::TestContextObject, }; @@ -29,7 +29,7 @@ fuzz_target!(|data: DumbFuzzData| { let prog = data.prog; let config = data.template.into(); let function_registry = FunctionRegistry::default(); - let syscall_registry = FunctionRegistry::>::default(); + let syscall_registry = SyscallRegistry::>::default(); if RequisiteVerifier::verify(&prog, &config, &SBPFVersion::V2, &function_registry, &syscall_registry).is_err() { // verify please @@ -41,6 +41,7 @@ fuzz_target!(|data: DumbFuzzData| { std::sync::Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + syscall_registry, )), SBPFVersion::V2, function_registry, diff --git a/fuzz/fuzz_targets/smart.rs b/fuzz/fuzz_targets/smart.rs index 0ecb535b..2b8a46f0 100644 --- a/fuzz/fuzz_targets/smart.rs +++ b/fuzz/fuzz_targets/smart.rs @@ -10,7 +10,7 @@ use solana_rbpf::{ elf::Executable, insn_builder::{Arch, IntoBytes}, memory_region::MemoryRegion, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion}, verifier::{RequisiteVerifier, Verifier}, vm::TestContextObject, }; @@ -33,7 +33,7 @@ fuzz_target!(|data: FuzzData| { let prog = make_program(&data.prog, data.arch); let config = data.template.into(); let function_registry = FunctionRegistry::default(); - let syscall_registry = FunctionRegistry::>::default(); + let syscall_registry = SyscallRegistry::>::default(); if RequisiteVerifier::verify( prog.into_bytes(), @@ -53,6 +53,7 @@ fuzz_target!(|data: FuzzData| { std::sync::Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + syscall_registry, )), SBPFVersion::V2, function_registry, diff --git a/fuzz/fuzz_targets/smart_jit_diff.rs b/fuzz/fuzz_targets/smart_jit_diff.rs index 87203ca2..b7a7bb50 100644 --- a/fuzz/fuzz_targets/smart_jit_diff.rs +++ b/fuzz/fuzz_targets/smart_jit_diff.rs @@ -8,7 +8,7 @@ use solana_rbpf::{ elf::Executable, insn_builder::{Arch, Instruction, IntoBytes}, memory_region::MemoryRegion, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion}, verifier::{RequisiteVerifier, Verifier}, vm::TestContextObject, }; @@ -40,7 +40,7 @@ fuzz_target!(|data: FuzzData| { .push(); let config = data.template.into(); let function_registry = FunctionRegistry::default(); - let syscall_registry = FunctionRegistry::>::default(); + let syscall_registry = SyscallRegistry::>::default(); if RequisiteVerifier::verify( prog.into_bytes(), @@ -61,6 +61,7 @@ fuzz_target!(|data: FuzzData| { std::sync::Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + syscall_registry, )), SBPFVersion::V2, function_registry, diff --git a/fuzz/fuzz_targets/smarter_jit_diff.rs b/fuzz/fuzz_targets/smarter_jit_diff.rs index 6d77df41..9a63a39f 100644 --- a/fuzz/fuzz_targets/smarter_jit_diff.rs +++ b/fuzz/fuzz_targets/smarter_jit_diff.rs @@ -8,7 +8,7 @@ use solana_rbpf::{ elf::Executable, insn_builder::IntoBytes, memory_region::MemoryRegion, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion}, verifier::{RequisiteVerifier, Verifier}, vm::TestContextObject, }; @@ -30,7 +30,7 @@ fuzz_target!(|data: FuzzData| { let prog = make_program(&data.prog); let config = data.template.into(); let function_registry = FunctionRegistry::default(); - let syscall_registry = FunctionRegistry::>::default(); + let syscall_registry = SyscallRegistry::>::default(); if RequisiteVerifier::verify( prog.into_bytes(), @@ -51,6 +51,7 @@ fuzz_target!(|data: FuzzData| { std::sync::Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + syscall_registry, )), SBPFVersion::V2, function_registry, diff --git a/fuzz/fuzz_targets/verify_semantic_aware.rs b/fuzz/fuzz_targets/verify_semantic_aware.rs index 0c2cc09f..9580fbd0 100644 --- a/fuzz/fuzz_targets/verify_semantic_aware.rs +++ b/fuzz/fuzz_targets/verify_semantic_aware.rs @@ -5,7 +5,7 @@ use libfuzzer_sys::fuzz_target; use semantic_aware::*; use solana_rbpf::{ insn_builder::IntoBytes, - program::{BuiltinFunction, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, FunctionRegistry, SyscallRegistry, SBPFVersion}, verifier::{RequisiteVerifier, Verifier}, vm::TestContextObject, }; @@ -25,7 +25,7 @@ fuzz_target!(|data: FuzzData| { let prog = make_program(&data.prog); let config = data.template.into(); let function_registry = FunctionRegistry::default(); - let syscall_registry = FunctionRegistry::>::default(); + let syscall_registry = SyscallRegistry::>::default(); RequisiteVerifier::verify( prog.into_bytes(), diff --git a/src/elf.rs b/src/elf.rs index f907705c..c54f5564 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -107,6 +107,9 @@ pub enum ElfError { /// Invalid program header #[error("Invalid ELF program header")] InvalidProgramHeader, + /// Invalid syscall code + #[error("Invalid syscall code")] + InvalidSyscallCode, } impl From for ElfError { @@ -315,7 +318,7 @@ impl Executable { self.get_config(), self.get_sbpf_version(), self.get_function_registry(), - self.loader.get_function_registry(), + self.loader.get_syscall_registry(), )?; Ok(()) } @@ -1144,6 +1147,7 @@ pub(crate) fn get_ro_region(ro_section: &Section, elf: &[u8]) -> MemoryRegion { #[cfg(test)] mod test { use super::*; + use crate::program::SyscallRegistry; use crate::{ elf_parser::{ // FIXME consts::{ELFCLASS32, ELFDATA2MSB, ET_REL}, @@ -1174,6 +1178,7 @@ mod test { Arc::new(BuiltinProgram::new_loader( Config::default(), function_registry, + SyscallRegistry::default(), )) } @@ -1929,6 +1934,7 @@ mod test { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), ); let elf_bytes = std::fs::read("tests/elfs/syscall_reloc_64_32_sbpfv1.so") .expect("failed to read elf file"); diff --git a/src/jit.rs b/src/jit.rs index d17abd19..e8c324e7 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -1696,7 +1696,9 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> { mod tests { use super::*; use crate::{ - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{ + BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion, SyscallRegistry, + }, syscalls, vm::TestContextObject, }; @@ -1748,7 +1750,8 @@ mod tests { function_registry .register_function_hashed(*b"gather_bytes", syscalls::SyscallGatherBytes::vm) .unwrap(); - let loader = BuiltinProgram::new_loader(config, function_registry); + let syscall_registry = SyscallRegistry::default(); + let loader = BuiltinProgram::new_loader(config, function_registry, syscall_registry); let mut function_registry = FunctionRegistry::default(); function_registry .register_function(8, *b"function_foo", 8) diff --git a/src/program.rs b/src/program.rs index 1f817c02..c4829f22 100644 --- a/src/program.rs +++ b/src/program.rs @@ -216,6 +216,40 @@ impl FunctionRegistry { } } +/// A registry to operate with static syscalls represented by integers. +#[derive(PartialEq, Eq)] +pub struct SyscallRegistry { + look_up: Vec<(Vec, T)>, +} + +impl Default for SyscallRegistry { + fn default() -> Self { + SyscallRegistry::new(Vec::new()) + } +} + +impl SyscallRegistry { + /// Create a new registry based on a previously created vector of registrations. + /// We expect the vector to be dense, containing one function per position. + pub fn new(registry: Vec<(Vec, T)>) -> Self { + SyscallRegistry { look_up: registry } + } + + /// Retrieve a syscall from the registry + pub fn lookup_syscall(&self, code: usize) -> Result<(&[u8], T), ElfError> { + if code == 0 { + return Err(ElfError::InvalidSyscallCode); + } + + self.look_up + .get(code.saturating_sub(1)) + .as_ref() + .map_or(Err(ElfError::InvalidSyscallCode), |(name, value)| { + Ok((name.as_slice(), *value)) + }) + } +} + /// Syscall function without context pub type BuiltinFunction = fn(*mut EbpfVm, u64, u64, u64, u64, u64); @@ -226,6 +260,8 @@ pub struct BuiltinProgram { config: Option>, /// Function pointers by symbol functions: FunctionRegistry>, + /// Syscalls registry for this loader + syscalls: SyscallRegistry>, } impl PartialEq for BuiltinProgram { @@ -236,18 +272,27 @@ impl PartialEq for BuiltinProgram { impl BuiltinProgram { /// Constructs a loader built-in program - pub fn new_loader(config: Config, functions: FunctionRegistry>) -> Self { + pub fn new_loader( + config: Config, + functions: FunctionRegistry>, + syscalls: SyscallRegistry>, + ) -> Self { Self { config: Some(Box::new(config)), functions, + syscalls, } } /// Constructs a built-in program - pub fn new_builtin(functions: FunctionRegistry>) -> Self { + pub fn new_builtin( + functions: FunctionRegistry>, + syscalls: SyscallRegistry>, + ) -> Self { Self { config: None, functions, + syscalls, } } @@ -256,6 +301,7 @@ impl BuiltinProgram { Self { config: Some(Box::default()), functions: FunctionRegistry::default(), + syscalls: SyscallRegistry::default(), } } @@ -269,6 +315,11 @@ impl BuiltinProgram { &self.functions } + /// Get the syscall registry + pub fn get_syscall_registry(&self) -> &SyscallRegistry> { + &self.syscalls + } + /// Calculate memory size pub fn mem_size(&self) -> usize { std::mem::size_of::() @@ -378,10 +429,38 @@ mod tests { function_registry_c .register_function_hashed(*b"log_64", syscalls::SyscallU64::vm) .unwrap(); - let builtin_program_a = BuiltinProgram::new_loader(Config::default(), function_registry_a); - let builtin_program_b = BuiltinProgram::new_loader(Config::default(), function_registry_b); + let builtin_program_a = BuiltinProgram::new_loader( + Config::default(), + function_registry_a, + SyscallRegistry::default(), + ); + let builtin_program_b = BuiltinProgram::new_loader( + Config::default(), + function_registry_b, + SyscallRegistry::default(), + ); assert_eq!(builtin_program_a, builtin_program_b); - let builtin_program_c = BuiltinProgram::new_loader(Config::default(), function_registry_c); + let builtin_program_c = BuiltinProgram::new_loader( + Config::default(), + function_registry_c, + SyscallRegistry::default(), + ); assert_ne!(builtin_program_a, builtin_program_c); } + + #[test] + fn test_syscall_registry() { + let registry_vec: Vec<(Vec, BuiltinFunction)> = + vec![(b"log".to_vec(), syscalls::SyscallString::vm)]; + let registry = SyscallRegistry::>::new(registry_vec); + + let lookup_result = registry.lookup_syscall(0); + assert_eq!(lookup_result.err().unwrap(), ElfError::InvalidSyscallCode); + + let lookup_result = registry.lookup_syscall(3); + assert_eq!(lookup_result.err().unwrap(), ElfError::InvalidSyscallCode); + + let lookup_result = registry.lookup_syscall(1); + assert!(lookup_result.is_ok()); + } } diff --git a/src/verifier.rs b/src/verifier.rs index 6f46a0a3..ac92d2f3 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -14,7 +14,7 @@ use crate::{ ebpf, - program::{BuiltinFunction, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, FunctionRegistry, SBPFVersion, SyscallRegistry}, vm::{Config, ContextObject}, }; use thiserror::Error; @@ -90,7 +90,7 @@ pub trait Verifier { config: &Config, sbpf_version: &SBPFVersion, function_registry: &FunctionRegistry, - syscall_registry: &FunctionRegistry>, + syscall_registry: &SyscallRegistry>, ) -> Result<(), VerifierError>; } @@ -154,14 +154,10 @@ fn check_jmp_offset( Ok(()) } -fn check_call_target( +fn check_call_target( key: u32, - function_registry: &FunctionRegistry, -) -> Result<(), VerifierError> -where - T: Copy, - T: PartialEq, -{ + function_registry: &FunctionRegistry, +) -> Result<(), VerifierError> { function_registry .lookup_by_key(key) .map(|_| ()) @@ -214,13 +210,23 @@ fn check_callx_register( Ok(()) } +fn check_syscall( + code: usize, + pc: usize, + registry: &SyscallRegistry>, +) -> Result<(), VerifierError> { + registry + .lookup_syscall(code) + .map_or(Err(VerifierError::InvalidFunction(pc)), |_| Ok(())) +} + /// Mandatory verifier for solana programs to run on-chain #[derive(Debug)] pub struct RequisiteVerifier {} impl Verifier for RequisiteVerifier { /// Check the program against the verifier's rules #[rustfmt::skip] - fn verify(prog: &[u8], _config: &Config, sbpf_version: &SBPFVersion, function_registry: &FunctionRegistry, syscall_registry: &FunctionRegistry>) -> Result<(), VerifierError> { + fn verify(prog: &[u8], _config: &Config, sbpf_version: &SBPFVersion, function_registry: &FunctionRegistry, syscall_registry: &SyscallRegistry>) -> Result<(), VerifierError> { check_prog_len(prog)?; let program_range = 0..prog.len() / ebpf::INSN_SIZE; @@ -386,13 +392,12 @@ impl Verifier for RequisiteVerifier { ebpf::JSLT_REG => { check_jmp_offset(prog, insn_ptr, &function_range)?; }, ebpf::JSLE_IMM => { check_jmp_offset(prog, insn_ptr, &function_range)?; }, ebpf::JSLE_REG => { check_jmp_offset(prog, insn_ptr, &function_range)?; }, - ebpf::CALL_IMM if sbpf_version.static_syscalls() && insn.src != 0 => { check_call_target(insn.imm as u32, function_registry)?; }, - ebpf::CALL_IMM if sbpf_version.static_syscalls() && insn.src == 0 => { check_call_target(insn.imm as u32, syscall_registry)?; }, + ebpf::CALL_IMM if sbpf_version.static_syscalls() => { check_call_target(insn.imm as u32, function_registry)?; }, ebpf::CALL_IMM => {}, ebpf::CALL_REG => { check_callx_register(&insn, insn_ptr, sbpf_version)?; }, ebpf::EXIT if !sbpf_version.static_syscalls() => {}, ebpf::RETURN if sbpf_version.static_syscalls() => {}, - ebpf::SYSCALL if sbpf_version.static_syscalls() => {}, + ebpf::SYSCALL if sbpf_version.static_syscalls() => { check_syscall(insn.imm as usize, insn_ptr, syscall_registry)?; }, _ => { return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr)); diff --git a/tests/assembler.rs b/tests/assembler.rs index 66df864d..77ac0618 100644 --- a/tests/assembler.rs +++ b/tests/assembler.rs @@ -8,7 +8,7 @@ extern crate solana_rbpf; extern crate test_utils; -use solana_rbpf::program::{FunctionRegistry, SBPFVersion}; +use solana_rbpf::program::{FunctionRegistry, SBPFVersion, SyscallRegistry}; use solana_rbpf::vm::Config; use solana_rbpf::{assembler::assemble, ebpf, program::BuiltinProgram, vm::TestContextObject}; use std::sync::Arc; @@ -19,7 +19,11 @@ fn asm(src: &str) -> Result, String> { } fn asm_with_config(src: &str, config: Config) -> Result, String> { - let loader = BuiltinProgram::new_loader(config, FunctionRegistry::default()); + let loader = BuiltinProgram::new_loader( + config, + FunctionRegistry::default(), + SyscallRegistry::default(), + ); let executable = assemble::(src, Arc::new(loader))?; let (_program_vm_addr, program) = executable.get_text_bytes(); Ok((0..program.len() / ebpf::INSN_SIZE) @@ -527,6 +531,7 @@ fn test_tcp_sack() { Arc::new(BuiltinProgram::new_loader( config, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); diff --git a/tests/disassembler.rs b/tests/disassembler.rs index e77d274f..cfb6d376 100644 --- a/tests/disassembler.rs +++ b/tests/disassembler.rs @@ -7,7 +7,7 @@ // copied, modified, or distributed except according to those terms. extern crate solana_rbpf; -use solana_rbpf::program::SBPFVersion; +use solana_rbpf::program::{SBPFVersion, SyscallRegistry}; use solana_rbpf::{ assembler::assemble, program::{BuiltinProgram, FunctionRegistry}, @@ -27,7 +27,11 @@ macro_rules! disasm { }}; ($src:expr, $config:expr) => {{ let src = $src; - let loader = BuiltinProgram::new_loader($config, FunctionRegistry::default()); + let loader = BuiltinProgram::new_loader( + $config, + FunctionRegistry::default(), + SyscallRegistry::default(), + ); let executable = assemble::(src, Arc::new(loader)).unwrap(); let analysis = Analysis::from_executable(&executable).unwrap(); let mut reasm = Vec::new(); diff --git a/tests/execution.rs b/tests/execution.rs index 312e1c47..21b30bf1 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -21,7 +21,7 @@ use solana_rbpf::{ elf::Executable, error::{EbpfError, ProgramResult}, memory_region::{AccessType, MemoryMapping, MemoryRegion}, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion, SyscallRegistry}, static_analysis::Analysis, syscalls, verifier::RequisiteVerifier, @@ -150,7 +150,7 @@ macro_rules! test_interpreter_and_jit_asm { config.enable_instruction_tracing = true; let mut function_registry = FunctionRegistry::>::default(); $(test_interpreter_and_jit!(register, function_registry, $location => $syscall_function);)* - let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry)); + let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry, SyscallRegistry::default())); let mut executable = assemble($source, loader).unwrap(); test_interpreter_and_jit!(executable, $mem, $context_object, $expected_result); } @@ -172,7 +172,7 @@ macro_rules! test_interpreter_and_jit_elf { { let mut function_registry = FunctionRegistry::>::default(); $(test_interpreter_and_jit!(register, function_registry, $location => $syscall_function);)* - let loader = Arc::new(BuiltinProgram::new_loader($config, function_registry)); + let loader = Arc::new(BuiltinProgram::new_loader($config, function_registry, SyscallRegistry::default())); let mut executable = Executable::::from_elf(&elf, loader).unwrap(); test_interpreter_and_jit!($verify, executable, $mem, $context_object, $expected_result); } @@ -1999,6 +1999,10 @@ fn test_stack1() { #[test] fn test_stack2() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " stb [r10-4], 0x01 @@ -2017,6 +2021,7 @@ fn test_stack2() { syscall bpf_gather_bytes xor r0, 0x2a2a2a2a exit", + config, [], ( "bpf_mem_frob" => syscalls::SyscallMemFrob::vm, @@ -2029,6 +2034,10 @@ fn test_stack2() { #[test] fn test_string_stack() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov r1, 0x78636261 @@ -2059,6 +2068,7 @@ fn test_string_stack() { jeq r1, r6, +1 mov r0, 0x0 exit", + config, [], ( "bpf_str_cmp" => syscalls::SyscallStrCmp::vm, @@ -2367,6 +2377,10 @@ fn test_bpf_to_bpf_scratch_registers() { #[test] fn test_syscall_parameter_on_stack() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r1, r10 @@ -2375,6 +2389,7 @@ fn test_syscall_parameter_on_stack() { syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -2560,12 +2575,17 @@ fn test_call_save() { #[test] fn test_err_syscall_string() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r1, 0x0 syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [72, 101, 108, 108, 111], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -2577,12 +2597,17 @@ fn test_err_syscall_string() { #[test] fn test_syscall_string() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r2, 0x5 syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [72, 101, 108, 108, 111], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -2594,6 +2619,10 @@ fn test_syscall_string() { #[test] fn test_syscall() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r1, 0xAA @@ -2604,6 +2633,7 @@ fn test_syscall() { syscall bpf_syscall_u64 mov64 r0, 0x0 exit", + config, [], ( "bpf_syscall_u64" => syscalls::SyscallU64::vm, @@ -2615,6 +2645,10 @@ fn test_syscall() { #[test] fn test_call_gather_bytes() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov r1, 1 @@ -2624,6 +2658,7 @@ fn test_call_gather_bytes() { mov r5, 5 syscall bpf_gather_bytes exit", + config, [], ( "bpf_gather_bytes" => syscalls::SyscallGatherBytes::vm, @@ -2635,6 +2670,10 @@ fn test_call_gather_bytes() { #[test] fn test_call_memfrob() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov r6, r1 @@ -2644,6 +2683,7 @@ fn test_call_memfrob() { ldxdw r0, [r6] be64 r0 exit", + config, [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // ], @@ -2685,7 +2725,11 @@ declare_builtin_function!( function_registry .register_function_hashed(*b"nested_vm_syscall", SyscallNestedVm::vm) .unwrap(); - let loader = BuiltinProgram::new_loader(Config::default(), function_registry); + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; + let loader = BuiltinProgram::new_loader(config, function_registry, SyscallRegistry::default()); let mem = [depth as u8 - 1, throw as u8]; let mut executable = assemble::( " @@ -2783,12 +2827,17 @@ fn test_tight_infinite_recursion_callx() { #[test] fn test_instruction_count_syscall() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r2, 0x5 syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [72, 101, 108, 108, 111], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -2800,12 +2849,17 @@ fn test_instruction_count_syscall() { #[test] fn test_err_instruction_count_syscall_capped() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r2, 0x5 syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [72, 101, 108, 108, 111], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -2838,6 +2892,10 @@ fn test_non_terminate_early() { #[test] fn test_err_non_terminate_capped() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r6, 0x0 @@ -2850,6 +2908,7 @@ fn test_err_non_terminate_capped() { add64 r6, 0x1 ja -0x8 exit", + config.clone(), [], ( "bpf_trace_printf" => syscalls::SyscallTracePrintf::vm, @@ -2869,6 +2928,7 @@ fn test_err_non_terminate_capped() { add64 r6, 0x1 ja -0x8 exit", + config, [], ( "bpf_trace_printf" => syscalls::SyscallTracePrintf::vm, @@ -2985,6 +3045,10 @@ fn test_far_jumps() { #[test] fn test_symbol_relocation() { + let config = Config { + enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1, + ..Config::default() + }; test_interpreter_and_jit_asm!( " mov64 r1, r10 @@ -2993,6 +3057,7 @@ fn test_symbol_relocation() { syscall bpf_syscall_string mov64 r0, 0x0 exit", + config, [72, 101, 108, 108, 111], ( "bpf_syscall_string" => syscalls::SyscallString::vm, @@ -3388,6 +3453,7 @@ fn execute_generated_program(prog: &[u8]) -> bool { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), SBPFVersion::V2, FunctionRegistry::default(), @@ -4099,7 +4165,11 @@ fn test_invalid_exit_or_return() { ..Config::default() }; let function_registry = FunctionRegistry::>::default(); - let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry)); + let loader = Arc::new(BuiltinProgram::new_loader( + config, + function_registry, + SyscallRegistry::default(), + )); let mut executable = Executable::::from_text_bytes( prog, loader, diff --git a/tests/exercise_instructions.rs b/tests/exercise_instructions.rs index 659c5770..6acd1a0b 100644 --- a/tests/exercise_instructions.rs +++ b/tests/exercise_instructions.rs @@ -17,7 +17,7 @@ use solana_rbpf::{ assembler::assemble, ebpf, memory_region::MemoryRegion, - program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion, SyscallRegistry}, static_analysis::Analysis, verifier::RequisiteVerifier, vm::{Config, ContextObject, TestContextObject}, @@ -124,7 +124,7 @@ macro_rules! test_interpreter_and_jit_asm { config.enable_instruction_tracing = true; let mut function_registry = FunctionRegistry::>::default(); $(test_interpreter_and_jit!(register, function_registry, $location => $syscall_function);)* - let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry)); + let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry, SyscallRegistry::default())); let mut executable = assemble($source, loader).unwrap(); test_interpreter_and_jit!(executable, $mem, $context_object); } diff --git a/tests/verifier.rs b/tests/verifier.rs index 5fa54218..cabdd60d 100644 --- a/tests/verifier.rs +++ b/tests/verifier.rs @@ -22,6 +22,7 @@ extern crate solana_rbpf; extern crate thiserror; +use solana_rbpf::program::SyscallRegistry; use solana_rbpf::{ assembler::assemble, ebpf, @@ -49,7 +50,7 @@ impl Verifier for TautologyVerifier { _config: &Config, _sbpf_version: &SBPFVersion, _function_registry: &FunctionRegistry, - _syscall_registry: &FunctionRegistry>, + _syscall_registry: &SyscallRegistry>, ) -> std::result::Result<(), VerifierError> { Ok(()) } @@ -62,7 +63,7 @@ impl Verifier for ContradictionVerifier { _config: &Config, _sbpf_version: &SBPFVersion, _function_registry: &FunctionRegistry, - _syscall_registry: &FunctionRegistry>, + _syscall_registry: &SyscallRegistry>, ) -> std::result::Result<(), VerifierError> { Err(VerifierError::NoProgram) } @@ -167,6 +168,7 @@ fn test_verifier_err_invalid_reg_dst() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); @@ -190,6 +192,7 @@ fn test_verifier_err_invalid_reg_src() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); @@ -211,6 +214,7 @@ fn test_verifier_resize_stack_ptr_success() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); @@ -303,10 +307,10 @@ fn test_verifier_err_unknown_opcode() { } #[test] -#[should_panic(expected = "InvalidFunction(1811268606)")] +#[should_panic(expected = "InvalidFunction(2)")] fn test_verifier_unknown_sycall() { let prog = &[ - 0x85, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0xf5, 0x6b, // call 0x6bf5c3fe + 0x85, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // syscall 2 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // return ]; let executable = Executable::::from_text_bytes( @@ -322,18 +326,19 @@ fn test_verifier_unknown_sycall() { #[test] fn test_verifier_known_syscall() { let prog = &[ - 0x85, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0xf5, 0x6b, // call 0x6bf5c3fe + 0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // syscall 1 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // return ]; - let mut function_registry = FunctionRegistry::>::default(); - function_registry - .register_function(0x6bf5c3fe, b"my_syscall", syscalls::SyscallString::vm) - .unwrap(); + let syscalls: Vec<(Vec, BuiltinFunction)> = + vec![(b"my_syscall".to_vec(), syscalls::SyscallString::vm)]; + let syscall_registry = SyscallRegistry::>::new(syscalls); + let executable = Executable::::from_text_bytes( prog, Arc::new(BuiltinProgram::new_loader( Config::default(), - function_registry, + FunctionRegistry::default(), + syscall_registry, )), SBPFVersion::V2, FunctionRegistry::default(), @@ -413,6 +418,7 @@ fn test_sdiv_disabled() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); @@ -444,7 +450,7 @@ fn return_instr() { .unwrap(); let result = executable.verify::(); if sbpf_version == SBPFVersion::V2 { - assert!(result.is_ok()); + assert_error!(result, "VerifierError(InvalidFunction(1))"); } else { assert_error!(result, "VerifierError(UnknownOpCode(157, 2))"); } @@ -462,6 +468,7 @@ fn return_in_v2() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap(); @@ -480,6 +487,7 @@ fn function_without_return() { ..Config::default() }, FunctionRegistry::default(), + SyscallRegistry::default(), )), ) .unwrap();