diff --git a/Cargo.lock b/Cargo.lock index ce0d463f81..382a116046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6308,9 +6308,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df28dcb607dd56ab0022f99d3a9ff1ee0d87951315762c0b89e946c087ebbea" +checksum = "80a28c5dfe7e8af38daa39d6561c8e8b9ed7a2f900951ebe7362ad6348d36c73" dependencies = [ "byteorder", "combine", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f0ddaa5cd9..516b72cf03 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -42,7 +42,7 @@ solana-sdk = { path = "../sdk", version = "=1.11.0" } solana-transaction-status = { path = "../transaction-status", version = "=1.11.0" } solana-version = { path = "../version", version = "=1.11.0" } solana-vote-program = { path = "../programs/vote", version = "=1.11.0" } -solana_rbpf = "=0.2.30" +solana_rbpf = "=0.2.31" spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] } thiserror = "1.0.31" tiny-bip39 = "0.8.2" diff --git a/cli/src/program.rs b/cli/src/program.rs index 20d621a99c..2179e4cddc 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -25,7 +25,11 @@ use { tpu_client::{TpuClient, TpuClientConfig}, }, solana_program_runtime::invoke_context::InvokeContext, - solana_rbpf::{elf::Executable, verifier, vm::Config}, + solana_rbpf::{ + elf::Executable, + verifier::RequisiteVerifier, + vm::{Config, VerifiedExecutable}, + }, solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_sdk::{ account::Account, @@ -2079,9 +2083,8 @@ fn read_and_verify_elf(program_location: &str) -> Result, Box::from_elf( + let executable = Executable::::from_elf( &program_data, - Some(verifier::check), Config { reject_broken_elfs: true, ..Config::default() @@ -2090,6 +2093,12 @@ fn read_and_verify_elf(program_location: &str) -> Result, Box::from_executable( + executable, + ) + .map_err(|err| format!("ELF error: {}", err))?; + Ok(program_data) } diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 86634ddac7..d5655fe280 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -5516,9 +5516,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df28dcb607dd56ab0022f99d3a9ff1ee0d87951315762c0b89e946c087ebbea" +checksum = "80a28c5dfe7e8af38daa39d6561c8e8b9ed7a2f900951ebe7362ad6348d36c73" dependencies = [ "byteorder 1.4.3", "combine", diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index 078a968512..943173422e 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -33,7 +33,7 @@ solana-bpf-rust-realloc-invoke = { path = "rust/realloc_invoke", version = "=1.1 solana-cli-output = { path = "../../cli-output", version = "=1.11.0" } solana-logger = { path = "../../logger", version = "=1.11.0" } solana-measure = { path = "../../measure", version = "=1.11.0" } -solana_rbpf = "=0.2.30" +solana_rbpf = "=0.2.31" solana-runtime = { path = "../../runtime", version = "=1.11.0" } solana-program-runtime = { path = "../../program-runtime", version = "=1.11.0" } solana-sdk = { path = "../../sdk", version = "=1.11.0" } diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index f79194ce10..727afacc1b 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -15,7 +15,8 @@ use { solana_program_runtime::invoke_context::with_mock_invoke_context, solana_rbpf::{ elf::Executable, - vm::{Config, InstructionMeter, SyscallRegistry}, + verifier::RequisiteVerifier, + vm::{Config, InstructionMeter, SyscallRegistry, VerifiedExecutable}, }, solana_runtime::{ bank::Bank, @@ -81,7 +82,6 @@ fn bench_program_create_executable(bencher: &mut Bencher) { bencher.iter(|| { let _ = Executable::::from_elf( &elf, - None, Config::default(), SyscallRegistry::default(), ) @@ -105,17 +105,30 @@ fn bench_program_alu(bencher: &mut Bencher) { .get_compute_meter() .borrow_mut() .mock_set_remaining(std::i64::MAX as u64); - let mut executable = Executable::::from_elf( + let executable = Executable::::from_elf( &elf, - None, Config::default(), register_syscalls(invoke_context, true).unwrap(), ) .unwrap(); - Executable::::jit_compile(&mut executable).unwrap(); + + let mut verified_executable = VerifiedExecutable::< + RequisiteVerifier, + BpfError, + ThisInstructionMeter, + >::from_executable(executable) + .unwrap(); + + verified_executable.jit_compile().unwrap(); let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; - let mut vm = create_vm(&executable, &mut inner_iter, vec![], invoke_context).unwrap(); + let mut vm = create_vm( + &verified_executable, + &mut inner_iter, + vec![], + invoke_context, + ) + .unwrap(); println!("Interpreted:"); assert_eq!( @@ -222,15 +235,21 @@ fn bench_create_vm(bencher: &mut Bencher) { let executable = Executable::::from_elf( &elf, - None, Config::default(), register_syscalls(invoke_context, true).unwrap(), ) .unwrap(); + let verified_executable = VerifiedExecutable::< + RequisiteVerifier, + BpfError, + ThisInstructionMeter, + >::from_executable(executable) + .unwrap(); + bencher.iter(|| { let _ = create_vm( - &executable, + &verified_executable, serialized.as_slice_mut(), account_lengths.clone(), invoke_context, @@ -263,15 +282,22 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let executable = Executable::::from_elf( &elf, - None, Config::default(), register_syscalls(invoke_context, true).unwrap(), ) .unwrap(); + + let verified_executable = VerifiedExecutable::< + RequisiteVerifier, + BpfError, + ThisInstructionMeter, + >::from_executable(executable) + .unwrap(); + let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; let mut vm = create_vm( - &executable, + &verified_executable, serialized.as_slice_mut(), account_lengths, invoke_context, diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 079266d057..ec8ce962f3 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -25,7 +25,8 @@ use { solana_rbpf::{ elf::Executable, static_analysis::Analysis, - vm::{Config, Tracer}, + verifier::RequisiteVerifier, + vm::{Config, Tracer, VerifiedExecutable}, }, solana_runtime::{ bank::{ @@ -222,14 +223,20 @@ fn run_program(name: &str) -> u64 { reject_broken_elfs: true, ..Config::default() }; - let mut executable = Executable::::from_elf( + let executable = Executable::::from_elf( &data, - None, config, register_syscalls(invoke_context, true /* no sol_alloc_free */).unwrap(), ) .unwrap(); - Executable::::jit_compile(&mut executable).unwrap(); + + let mut verified_executable = VerifiedExecutable::< + RequisiteVerifier, + BpfError, + ThisInstructionMeter, + >::from_executable(executable) + .unwrap(); + verified_executable.jit_compile().unwrap(); let mut instruction_count = 0; let mut tracer = None; @@ -247,7 +254,7 @@ fn run_program(name: &str) -> u64 { let mut parameter_bytes = parameter_bytes.clone(); { let mut vm = create_vm( - &executable, + &verified_executable, parameter_bytes.as_slice_mut(), account_lengths.clone(), invoke_context, @@ -266,7 +273,9 @@ fn run_program(name: &str) -> u64 { if config.enable_instruction_tracing { if i == 1 { if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) { - let analysis = Analysis::from_executable(&executable).unwrap(); + let analysis = + Analysis::from_executable(verified_executable.get_executable()) + .unwrap(); let stdout = std::io::stdout(); println!("TRACE (interpreted):"); tracer @@ -280,7 +289,9 @@ fn run_program(name: &str) -> u64 { .unwrap(); assert!(false); } else if log_enabled!(Trace) { - let analysis = Analysis::from_executable(&executable).unwrap(); + let analysis = + Analysis::from_executable(verified_executable.get_executable()) + .unwrap(); let mut trace_buffer = Vec::::new(); tracer .as_ref() diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index c63f378592..a946e19c82 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -19,7 +19,7 @@ solana-metrics = { path = "../../metrics", version = "=1.11.0" } solana-program-runtime = { path = "../../program-runtime", version = "=1.11.0" } solana-sdk = { path = "../../sdk", version = "=1.11.0" } solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.11.0" } -solana_rbpf = "=0.2.30" +solana_rbpf = "=0.2.31" thiserror = "1.0" [dev-dependencies] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 6b1c3f77a9..f5711fc3d7 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -33,8 +33,8 @@ use { error::{EbpfError, UserDefinedError}, memory_region::MemoryRegion, static_analysis::Analysis, - verifier::{self, VerifierError}, - vm::{Config, EbpfVm, InstructionMeter}, + verifier::{RequisiteVerifier, VerifierError}, + vm::{Config, EbpfVm, InstructionMeter, VerifiedExecutable}, }, solana_sdk::{ bpf_loader, bpf_loader_deprecated, @@ -57,7 +57,7 @@ use { system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, transaction_context::{InstructionContext, TransactionContext}, }, - std::{cell::RefCell, fmt::Debug, pin::Pin, rc::Rc, sync::Arc}, + std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}, thiserror::Error, }; @@ -158,7 +158,7 @@ pub fn create_executor( // Warning, do not use `Config::default()` so that configuration here is explicit. }; let mut create_executor_metrics = executor_metrics::CreateMetrics::default(); - let mut executable = { + let executable = { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let programdata = instruction_context @@ -170,7 +170,6 @@ pub fn create_executor( .get_data() .get(programdata_offset..) .ok_or(InstructionError::AccountDataTooSmall)?, - None, config, syscall_registry, ); @@ -183,10 +182,12 @@ pub fn create_executor( executable } .map_err(|e| map_ebpf_error(invoke_context, e))?; - let text_bytes = executable.get_text_bytes().1; let mut verify_code_time = Measure::start("verify_code_time"); - verifier::check(text_bytes, &config) - .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e.into())))?; + let mut verified_executable = + VerifiedExecutable::::from_executable( + executable, + ) + .map_err(|e| map_ebpf_error(invoke_context, e))?; verify_code_time.stop(); create_executor_metrics.verify_code_us = verify_code_time.as_us(); invoke_context.timings.create_executor_verify_code_us = invoke_context @@ -195,8 +196,7 @@ pub fn create_executor( .saturating_add(create_executor_metrics.verify_code_us); if use_jit { let mut jit_compile_time = Measure::start("jit_compile_time"); - let jit_compile_result = - Executable::::jit_compile(&mut executable); + let jit_compile_result = verified_executable.jit_compile(); jit_compile_time.stop(); create_executor_metrics.jit_compile_us = jit_compile_time.as_us(); invoke_context.timings.create_executor_jit_compile_us = invoke_context @@ -210,7 +210,7 @@ pub fn create_executor( } create_executor_metrics.submit_datapoint(); Ok(Arc::new(BpfExecutor { - executable, + verified_executable, use_jit, })) } @@ -250,11 +250,11 @@ fn check_loader_id(id: &Pubkey) -> bool { /// Create the BPF virtual machine pub fn create_vm<'a, 'b>( - program: &'a Pin>>, + program: &'a VerifiedExecutable, parameter_bytes: &mut [u8], orig_account_lengths: Vec, invoke_context: &'a mut InvokeContext<'b>, -) -> Result, EbpfError> { +) -> Result, EbpfError> { let compute_budget = invoke_context.get_compute_budget(); let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH); if invoke_context @@ -1157,7 +1157,7 @@ impl InstructionMeter for ThisInstructionMeter { /// BPF Loader's Executor implementation pub struct BpfExecutor { - executable: Pin>>, + verified_executable: VerifiedExecutable, use_jit: bool, } @@ -1190,7 +1190,7 @@ impl Executor for BpfExecutor { let mut execute_time; let execution_result = { let mut vm = match create_vm( - &self.executable, + &self.verified_executable, parameter_bytes.as_slice_mut(), account_lengths, invoke_context, @@ -1222,7 +1222,8 @@ impl Executor for BpfExecutor { ); if log_enabled!(Trace) { let mut trace_buffer = Vec::::new(); - let analysis = Analysis::from_executable(&self.executable).unwrap(); + let analysis = + Analysis::from_executable(self.verified_executable.get_executable()).unwrap(); vm.get_tracer().write(&mut trace_buffer, &analysis).unwrap(); let trace_string = String::from_utf8(trace_buffer).unwrap(); trace!("BPF Program Instruction Trace:\n{}", trace_string); @@ -1305,7 +1306,7 @@ mod tests { super::*, rand::Rng, solana_program_runtime::invoke_context::mock_process_instruction, - solana_rbpf::vm::SyscallRegistry, + solana_rbpf::{verifier::Verifier, vm::SyscallRegistry}, solana_runtime::{bank::Bank, bank_client::BankClient}, solana_sdk::{ account::{ @@ -1374,6 +1375,13 @@ mod tests { program_account } + struct TautologyVerifier {} + impl Verifier for TautologyVerifier { + fn verify(_prog: &[u8], _config: &Config) -> std::result::Result<(), VerifierError> { + Ok(()) + } + } + #[test] #[should_panic(expected = "ExceededMaxInstructions(31, 10)")] fn test_bpf_loader_non_terminating_program() { @@ -1395,18 +1403,21 @@ mod tests { "entrypoint", ) .unwrap(); - let program = Executable::::from_text_bytes( + let executable = Executable::::from_text_bytes( program, - None, config, syscall_registry, bpf_functions, ) .unwrap(); + let verified_executable = VerifiedExecutable::< + TautologyVerifier, + BpfError, + TestInstructionMeter, + >::from_executable(executable) + .unwrap(); let input_region = MemoryRegion::new_writable(&mut input_mem, MM_INPUT_START); - let mut vm = - EbpfVm::::new(&program, &mut [], vec![input_region]) - .unwrap(); + let mut vm = EbpfVm::new(&verified_executable, &mut [], vec![input_region]).unwrap(); let mut instruction_meter = TestInstructionMeter { remaining: 10 }; vm.execute_program_interpreted(&mut instruction_meter) .unwrap(); @@ -1418,7 +1429,7 @@ mod tests { let prog = &[ 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // first half of lddw ]; - verifier::check(prog, &Config::default()).unwrap(); + RequisiteVerifier::verify(prog, &Config::default()).unwrap(); } #[test] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d6299e8b9d..f4813d9eb0 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -13,6 +13,7 @@ use { error::EbpfError, memory_region::{AccessType, MemoryMapping}, question_mark, + verifier::RequisiteVerifier, vm::{EbpfVm, SyscallObject, SyscallRegistry}, }, solana_sdk::{ @@ -384,7 +385,7 @@ pub fn register_syscalls( } pub fn bind_syscall_context_objects<'a, 'b>( - vm: &mut EbpfVm<'a, BpfError, crate::ThisInstructionMeter>, + vm: &mut EbpfVm<'a, RequisiteVerifier, BpfError, crate::ThisInstructionMeter>, invoke_context: &'a mut InvokeContext<'b>, heap: AlignedMemory, orig_account_lengths: Vec, diff --git a/rbpf-cli/Cargo.toml b/rbpf-cli/Cargo.toml index 5c6808a592..4c76d7eb16 100644 --- a/rbpf-cli/Cargo.toml +++ b/rbpf-cli/Cargo.toml @@ -17,4 +17,4 @@ solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.11. solana-logger = { path = "../logger", version = "=1.11.0" } solana-program-runtime = { path = "../program-runtime", version = "=1.11.0" } solana-sdk = { path = "../sdk", version = "=1.11.0" } -solana_rbpf = "=0.2.30" +solana_rbpf = "=0.2.31" diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index 46f2852d9f..13601e549c 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -11,8 +11,8 @@ use { assembler::assemble, elf::Executable, static_analysis::Analysis, - verifier::check, - vm::{Config, DynamicAnalysis}, + verifier::RequisiteVerifier, + vm::{Config, DynamicAnalysis, VerifiedExecutable}, }, solana_sdk::{ account::AccountSharedData, bpf_loader, instruction::AccountMeta, pubkey::Pubkey, @@ -152,12 +152,6 @@ native machine code before execting it in the virtual machine.", .short('p') .long("profile"), ) - .arg( - Arg::new("verify") - .help("Run the verifier before execution or disassembly") - .short('v') - .long("verify"), - ) .arg( Arg::new("output_format") .help("Return information in specified output format") @@ -250,30 +244,27 @@ native machine code before execting it in the virtual machine.", let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); let syscall_registry = register_syscalls(&mut invoke_context, true).unwrap(); - let mut executable = if magic == [0x7f, 0x45, 0x4c, 0x46] { - Executable::::from_elf( - &contents, - None, - config, - syscall_registry, - ) - .map_err(|err| format!("Executable constructor failed: {:?}", err)) + let executable = if magic == [0x7f, 0x45, 0x4c, 0x46] { + Executable::::from_elf(&contents, config, syscall_registry) + .map_err(|err| format!("Executable constructor failed: {:?}", err)) } else { assemble::( std::str::from_utf8(contents.as_slice()).unwrap(), - None, config, syscall_registry, ) } .unwrap(); - if matches.is_present("verify") { - let text_bytes = executable.get_text_bytes().1; - check(text_bytes, &config).unwrap(); - } - Executable::::jit_compile(&mut executable).unwrap(); - let mut analysis = LazyAnalysis::new(&executable); + let mut verified_executable = + VerifiedExecutable::::from_executable( + executable, + ) + .map_err(|err| format!("Executable verifier failed: {:?}", err)) + .unwrap(); + + verified_executable.jit_compile().unwrap(); + let mut analysis = LazyAnalysis::new(verified_executable.get_executable()); match matches.value_of("use") { Some("cfg") => { @@ -293,7 +284,7 @@ native machine code before execting it in the virtual machine.", } let mut vm = create_vm( - &executable, + &verified_executable, parameter_bytes.as_slice_mut(), account_lengths, &mut invoke_context, diff --git a/sdk/bpf/dependencies/sbf-tools b/sdk/bpf/dependencies/sbf-tools new file mode 120000 index 0000000000..47391f01e7 --- /dev/null +++ b/sdk/bpf/dependencies/sbf-tools @@ -0,0 +1 @@ +/Users/jack/.cache/solana/v1.27/sbf-tools \ No newline at end of file