From 424666e3415d0a9184e9a12e48346fb1212feaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 6 Sep 2023 10:54:15 +0200 Subject: [PATCH] Bump solana_rbpf to v0.7.0 (#33104) * Upgrades RBPF in Cargo.toml * Adjustments to updated interfaces. --- Cargo.lock | 5 +- Cargo.toml | 2 +- cli/src/program.rs | 16 ++- ledger-tool/src/program.rs | 25 +++-- program-runtime/src/invoke_context.rs | 3 +- program-runtime/src/loaded_programs.rs | 83 ++++++++------- programs/bpf_loader/Cargo.toml | 2 +- programs/bpf_loader/src/lib.rs | 53 +++------- programs/bpf_loader/src/syscalls/mod.rs | 97 +++++++++--------- programs/loader-v4/Cargo.toml | 1 - programs/loader-v4/src/lib.rs | 85 +++++++++------ programs/loader-v4/test_elfs/out/noop.so | Bin 1768 -> 0 bytes .../loader-v4/test_elfs/out/relative_call.so | Bin 0 -> 5384 bytes programs/loader-v4/test_elfs/out/rodata.so | Bin 1904 -> 0 bytes .../loader-v4/test_elfs/out/rodata_section.so | Bin 0 -> 5424 bytes programs/sbf/Cargo.lock | 6 +- programs/sbf/Cargo.toml | 2 +- programs/sbf/benches/bpf_loader.rs | 68 +++++------- 18 files changed, 214 insertions(+), 234 deletions(-) delete mode 100755 programs/loader-v4/test_elfs/out/noop.so create mode 100644 programs/loader-v4/test_elfs/out/relative_call.so delete mode 100755 programs/loader-v4/test_elfs/out/rodata.so create mode 100644 programs/loader-v4/test_elfs/out/rodata_section.so diff --git a/Cargo.lock b/Cargo.lock index d14603617..551b056c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6255,7 +6255,6 @@ version = "1.17.0" dependencies = [ "bincode", "log", - "rand 0.8.5", "solana-measure", "solana-program-runtime", "solana-sdk", @@ -7528,9 +7527,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3082ec3a1d4ef7879eb5b84916d5acde057abd59733eec3647e0ab8885283ef" +checksum = "339e8963a8e2721227e46cf7a8488957db94cde0f35d3a769e292baaebdbeb44" dependencies = [ "byteorder", "combine", diff --git a/Cargo.toml b/Cargo.toml index 8be6e0ef6..0c7669ea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -294,7 +294,7 @@ siphasher = "0.3.11" smpl_jwt = "0.7.1" socket2 = "0.5.3" soketto = "0.7" -solana_rbpf = "=0.6.0" +solana_rbpf = "=0.7.0" solana-account-decoder = { path = "account-decoder", version = "=1.17.0" } solana-accounts-db = { path = "accounts-db", version = "=1.17.0" } solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.17.0" } diff --git a/cli/src/program.rs b/cli/src/program.rs index 61a470c91..81f6b3a3f 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -27,10 +27,7 @@ use { tpu_client::{TpuClient, TpuClientConfig}, }, solana_program_runtime::{compute_budget::ComputeBudget, invoke_context::InvokeContext}, - solana_rbpf::{ - elf::Executable, - verifier::{RequisiteVerifier, TautologyVerifier}, - }, + solana_rbpf::{elf::Executable, verifier::RequisiteVerifier}, solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_rpc_client::rpc_client::RpcClient, solana_rpc_client_api::{ @@ -2033,13 +2030,12 @@ fn read_and_verify_elf(program_location: &str) -> Result, Box::from_elf( - &program_data, - Arc::new(program_runtime_environment), - ) - .map_err(|err| format!("ELF error: {err}"))?; + let executable = + Executable::::from_elf(&program_data, Arc::new(program_runtime_environment)) + .map_err(|err| format!("ELF error: {err}"))?; - let _ = Executable::::verified(executable) + executable + .verify::() .map_err(|err| format!("ELF error: {err}"))?; Ok(program_data) diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index 7ed1ee06f..434919095 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -283,11 +283,11 @@ impl Debug for Output { // https://github.com/rust-lang/rust/issues/74465 struct LazyAnalysis<'a, 'b> { analysis: Option>, - executable: &'a Executable>, + executable: &'a Executable>, } impl<'a, 'b> LazyAnalysis<'a, 'b> { - fn new(executable: &'a Executable>) -> Self { + fn new(executable: &'a Executable>) -> Self { Self { analysis: None, executable, @@ -330,7 +330,7 @@ fn load_program<'a>( filename: &Path, program_id: Pubkey, invoke_context: &InvokeContext<'a>, -) -> Executable> { +) -> Executable> { let mut file = File::open(filename).unwrap(); let mut magic = [0u8; 4]; file.read_exact(&mut magic).unwrap(); @@ -374,22 +374,25 @@ fn load_program<'a>( Err(err) => Err(format!("Loading executable failed: {err:?}")), } } else { - let executable = assemble::( + assemble::( std::str::from_utf8(contents.as_slice()).unwrap(), Arc::new(program_runtime_environment), ) - .unwrap(); - Executable::::verified(executable) - .map_err(|err| format!("Assembling executable failed: {err:?}")) + .map_err(|err| format!("Assembling executable failed: {err:?}")) + .and_then(|executable| { + executable + .verify::() + .map_err(|err| format!("Verifying executable failed: {err:?}"))?; + Ok(executable) + }) } .unwrap(); #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))] verified_executable.jit_compile().unwrap(); unsafe { - std::mem::transmute::< - Executable>, - Executable>, - >(verified_executable) + std::mem::transmute::>, Executable>>( + verified_executable, + ) } } diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index a105048ac..12f82300d 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -748,7 +748,8 @@ impl<'a> InvokeContext<'a> { .ok_or(InstructionError::UnsupportedProgramId)?; let process_instruction = match &entry.program { LoadedProgramType::Builtin(program) => program - .lookup_function(ENTRYPOINT_KEY) + .get_function_registry() + .lookup_by_key(ENTRYPOINT_KEY) .map(|(_name, process_instruction)| process_instruction), _ => None, } diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index 73b5b8660..77246479e 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -1,5 +1,3 @@ -#[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))] -use solana_rbpf::error::EbpfError; use { crate::{ invoke_context::{InvokeContext, ProcessInstructionWithContext}, @@ -9,7 +7,11 @@ use { log::{debug, log_enabled, trace}, percentage::PercentageInteger, solana_measure::measure::Measure, - solana_rbpf::{elf::Executable, verifier::RequisiteVerifier, vm::BuiltinProgram}, + solana_rbpf::{ + elf::{Executable, FunctionRegistry}, + verifier::RequisiteVerifier, + vm::{BuiltinProgram, Config}, + }, solana_sdk::{ bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock::Slot, loader_v4, pubkey::Pubkey, saturating_add_assign, @@ -66,9 +68,9 @@ pub enum LoadedProgramType { DelayVisibility, /// Successfully verified but not currently compiled, used to track usage statistics when a compiled program is evicted from memory. Unloaded(Arc>>), - LegacyV0(Executable>), - LegacyV1(Executable>), - Typed(Executable>), + LegacyV0(Executable>), + LegacyV1(Executable>), + Typed(Executable>), #[cfg(test)] TestLoaded(Arc>>), Builtin(BuiltinProgram>), @@ -228,39 +230,35 @@ impl LoadedProgram { metrics: &mut LoadProgramMetrics, ) -> Result> { let mut load_elf_time = Measure::start("load_elf_time"); - let executable = Executable::load(elf_bytes, program_runtime_environment.clone())?; + let mut executable = Executable::load(elf_bytes, program_runtime_environment.clone())?; load_elf_time.stop(); metrics.load_elf_us = load_elf_time.as_us(); let mut verify_code_time = Measure::start("verify_code_time"); - - // Allowing mut here, since it may be needed for jit compile, which is under a config flag - #[allow(unused_mut)] - let mut program = if bpf_loader_deprecated::check_id(loader_key) { - LoadedProgramType::LegacyV0(Executable::verified(executable)?) - } else if bpf_loader::check_id(loader_key) || bpf_loader_upgradeable::check_id(loader_key) { - LoadedProgramType::LegacyV1(Executable::verified(executable)?) - } else if loader_v4::check_id(loader_key) { - LoadedProgramType::Typed(Executable::verified(executable)?) - } else { - panic!(); - }; + executable.verify::()?; verify_code_time.stop(); metrics.verify_code_us = verify_code_time.as_us(); #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))] { let mut jit_compile_time = Measure::start("jit_compile_time"); - match &mut program { - LoadedProgramType::LegacyV0(executable) => executable.jit_compile(), - LoadedProgramType::LegacyV1(executable) => executable.jit_compile(), - LoadedProgramType::Typed(executable) => executable.jit_compile(), - _ => Err(EbpfError::JitNotCompiled), - }?; + executable.jit_compile()?; jit_compile_time.stop(); metrics.jit_compile_us = jit_compile_time.as_us(); } + // Allowing mut here, since it may be needed for jit compile, which is under a config flag + #[allow(unused_mut)] + let mut program = if bpf_loader_deprecated::check_id(loader_key) { + LoadedProgramType::LegacyV0(executable) + } else if bpf_loader::check_id(loader_key) || bpf_loader_upgradeable::check_id(loader_key) { + LoadedProgramType::LegacyV1(executable) + } else if loader_v4::check_id(loader_key) { + LoadedProgramType::Typed(executable) + } else { + panic!(); + }; + Ok(Self { deployment_slot, account_size, @@ -298,9 +296,9 @@ impl LoadedProgram { account_size: usize, entrypoint: ProcessInstructionWithContext, ) -> Self { - let mut program = BuiltinProgram::default(); - program - .register_function(b"entrypoint", entrypoint) + let mut function_registry = FunctionRegistry::default(); + function_registry + .register_function_hashed(*b"entrypoint", entrypoint) .unwrap(); Self { deployment_slot, @@ -308,7 +306,7 @@ impl LoadedProgram { effective_slot: deployment_slot, maybe_expiration_slot: None, tx_usage_counter: AtomicU64::new(0), - program: LoadedProgramType::Builtin(program), + program: LoadedProgramType::Builtin(BuiltinProgram::new_builtin(function_registry)), ix_usage_counter: AtomicU64::new(0), } } @@ -347,7 +345,7 @@ impl LoadedProgram { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ProgramRuntimeEnvironments { /// Globally shared RBPF config and syscall registry pub program_runtime_v1: Arc>>, @@ -355,6 +353,19 @@ pub struct ProgramRuntimeEnvironments { pub program_runtime_v2: Arc>>, } +impl Default for ProgramRuntimeEnvironments { + fn default() -> Self { + let empty_loader = Arc::new(BuiltinProgram::new_loader( + Config::default(), + FunctionRegistry::default(), + )); + Self { + program_runtime_v1: empty_loader.clone(), + program_runtime_v2: empty_loader, + } + } +} + #[derive(Debug, Default)] pub struct LoadedPrograms { /// A two level index: @@ -832,7 +843,7 @@ mod tests { }, assert_matches::assert_matches, percentage::Percentage, - solana_rbpf::vm::{BuiltinProgram, Config}, + solana_rbpf::vm::BuiltinProgram, solana_sdk::{clock::Slot, pubkey::Pubkey}, std::{ ops::ControlFlow, @@ -845,7 +856,7 @@ mod tests { fn new_test_builtin_program(deployment_slot: Slot, effective_slot: Slot) -> Arc { Arc::new(LoadedProgram { - program: LoadedProgramType::Builtin(BuiltinProgram::default()), + program: LoadedProgramType::Builtin(BuiltinProgram::new_mock()), account_size: 0, deployment_slot, effective_slot, @@ -920,7 +931,7 @@ mod tests { programs.push((program1, *deployment_slot, usage_counter)); }); - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); for slot in 21..31 { set_tombstone( &mut cache, @@ -1118,7 +1129,7 @@ mod tests { fn test_replace_tombstones() { let mut cache = LoadedPrograms::default(); let program1 = Pubkey::new_unique(); - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); set_tombstone( &mut cache, program1, @@ -1134,7 +1145,7 @@ mod tests { #[test] fn test_tombstone() { - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); let tombstone = LoadedProgram::new_tombstone(0, LoadedProgramType::FailedVerification(env.clone())); assert_matches!(tombstone.program, LoadedProgramType::FailedVerification(_)); @@ -1359,7 +1370,7 @@ mod tests { usage_counter: AtomicU64, expiry: Option, ) -> Arc { - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); Arc::new(LoadedProgram { program: LoadedProgramType::TestLoaded(env), account_size: 0, diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index f979b7368..16a52c079 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -14,7 +14,6 @@ bincode = { workspace = true } byteorder = { workspace = true } libsecp256k1 = { workspace = true } log = { workspace = true } -rand = { workspace = true } scopeguard = { workspace = true } solana-measure = { workspace = true } solana-program-runtime = { workspace = true } @@ -26,6 +25,7 @@ thiserror = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } memoffset = { workspace = true } +rand = { workspace = true } solana-sdk = { workspace = true, features = ["dev-context-only-utils"] } [lib] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index ad4445a4d..342d38363 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -22,7 +22,6 @@ use { elf::Executable, error::EbpfError, memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion}, - verifier::RequisiteVerifier, vm::{BuiltinProgram, ContextObject, EbpfVm, ProgramResult}, }, solana_sdk::{ @@ -191,7 +190,7 @@ pub fn calculate_heap_cost(heap_size: u64, heap_cost: u64, enable_rounding_fix: /// Only used in macro, do not use directly! pub fn create_vm<'a, 'b>( - program: &'a Executable>, + program: &'a Executable>, regions: Vec, accounts_metadata: Vec, invoke_context: &'a mut InvokeContext<'b>, @@ -285,24 +284,21 @@ macro_rules! create_vm { #[macro_export] macro_rules! mock_create_vm { ($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => { - let loader = std::sync::Arc::new(BuiltinProgram::new_loader( - solana_rbpf::vm::Config::default(), - )); - let function_registry = solana_rbpf::vm::FunctionRegistry::default(); - let executable = solana_rbpf::elf::Executable::< - solana_rbpf::verifier::TautologyVerifier, - InvokeContext, - >::from_text_bytes( + let loader = std::sync::Arc::new(BuiltinProgram::new_mock()); + let function_registry = solana_rbpf::elf::FunctionRegistry::default(); + let executable = solana_rbpf::elf::Executable::::from_text_bytes( &[0x95, 0, 0, 0, 0, 0, 0, 0], loader, SBPFVersion::V2, function_registry, ) .unwrap(); - let verified_executable = solana_rbpf::elf::Executable::verified(executable).unwrap(); + executable + .verify::() + .unwrap(); $crate::create_vm!( $vm, - &verified_executable, + &executable, $additional_regions, $accounts_metadata, $invoke_context, @@ -311,7 +307,7 @@ macro_rules! mock_create_vm { } fn create_memory_mapping<'a, 'b, C: ContextObject>( - executable: &'a Executable, + executable: &'a Executable, stack: &'b mut AlignedMemory<{ HOST_ALIGN }>, heap: &'b mut AlignedMemory<{ HOST_ALIGN }>, additional_regions: Vec, @@ -1483,14 +1479,12 @@ fn process_loader_instruction(invoke_context: &mut InvokeContext) -> Result<(), } fn execute<'a, 'b: 'a>( - executable: &'a Executable>, + executable: &'a Executable>, invoke_context: &'a mut InvokeContext<'b>, ) -> Result<(), Box> { // We dropped the lifetime tracking in the Executor by setting it to 'static, // thus we need to reintroduce the correct lifetime of InvokeContext here again. - let executable = unsafe { - mem::transmute::<_, &'a Executable>>(executable) - }; + let executable = unsafe { mem::transmute::<_, &'a Executable>>(executable) }; let log_collector = invoke_context.get_log_collector(); let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; @@ -1728,11 +1722,7 @@ mod tests { solana_program_runtime::{ invoke_context::mock_process_instruction, with_mock_invoke_context, }, - solana_rbpf::{ - elf::SBPFVersion, - verifier::Verifier, - vm::{Config, ContextObject, FunctionRegistry}, - }, + solana_rbpf::vm::ContextObject, solana_sdk::{ account::{ create_account_shared_data_for_test as create_account_for_test, AccountSharedData, @@ -1796,21 +1786,6 @@ mod tests { program_account } - #[test] - #[should_panic(expected = "LDDWCannotBeLast")] - fn test_bpf_loader_check_load_dw() { - let prog = &[ - 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // first half of lddw - ]; - RequisiteVerifier::verify( - prog, - &Config::default(), - &SBPFVersion::V2, - &FunctionRegistry::default(), - ) - .unwrap(); - } - #[test] fn test_bpf_loader_write() { let loader_id = bpf_loader::id(); @@ -4103,7 +4078,7 @@ mod tests { let transaction_accounts = vec![]; with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts); let program_id = Pubkey::new_unique(); - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); let program = LoadedProgram { program: LoadedProgramType::Unloaded(env), account_size: 0, @@ -4143,7 +4118,7 @@ mod tests { let transaction_accounts = vec![]; with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts); let program_id = Pubkey::new_unique(); - let env = Arc::new(BuiltinProgram::new_loader(Config::default())); + let env = Arc::new(BuiltinProgram::new_mock()); let program = LoadedProgram { program: LoadedProgramType::Unloaded(env), account_size: 0, diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 2a52bd9aa..eb31edf3c 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -16,8 +16,9 @@ use { stable_log, timings::ExecuteTimings, }, solana_rbpf::{ + elf::FunctionRegistry, memory_region::{AccessType, MemoryMapping}, - vm::{BuiltinProgram, Config, ProgramResult, PROGRAM_ENVIRONMENT_KEY_SHIFT}, + vm::{BuiltinFunction, BuiltinProgram, Config, ProgramResult}, }, solana_sdk::{ account::{ReadableAccount, WritableAccount}, @@ -139,9 +140,9 @@ fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result< macro_rules! register_feature_gated_function { ($result:expr, $is_feature_active:expr, $name:expr, $call:expr $(,)?) => { if $is_feature_active { - $result.register_function($name, $call) + $result.register_function_hashed($name, $call) } else { - Ok(()) + Ok(0) } }; } @@ -167,7 +168,6 @@ pub fn create_program_runtime_environment_v1<'a>( // When adding new features for RBPF here, // also add them to `Bank::apply_builtin_program_feature_transitions()`. - use rand::Rng; let config = Config { max_call_depth: compute_budget.max_call_depth, stack_frame_size: compute_budget.stack_frame_size, @@ -180,10 +180,7 @@ pub fn create_program_runtime_environment_v1<'a>( reject_broken_elfs: reject_deployment_of_broken_elfs, noop_instruction_rate: 256, sanitize_user_provided_values: true, - runtime_environment_key: rand::thread_rng() - .gen::() - .checked_shr(PROGRAM_ENVIRONMENT_KEY_SHIFT) - .unwrap_or(0), + encrypt_runtime_environment: true, external_internal_function_hash_collision: feature_set .is_active(&error_on_syscall_bpf_function_hash_collisions::id()), reject_callx_r10: feature_set.is_active(&reject_callx_r10::id()), @@ -194,44 +191,44 @@ pub fn create_program_runtime_environment_v1<'a>( aligned_memory_mapping: !feature_set.is_active(&bpf_account_data_direct_mapping::id()), // Warning, do not use `Config::default()` so that configuration here is explicit. }; - let mut result = BuiltinProgram::new_loader(config); + let mut result = FunctionRegistry::>::default(); // Abort - result.register_function(b"abort", SyscallAbort::call)?; + result.register_function_hashed(*b"abort", SyscallAbort::call)?; // Panic - result.register_function(b"sol_panic_", SyscallPanic::call)?; + result.register_function_hashed(*b"sol_panic_", SyscallPanic::call)?; // Logging - result.register_function(b"sol_log_", SyscallLog::call)?; - result.register_function(b"sol_log_64_", SyscallLogU64::call)?; - result.register_function(b"sol_log_compute_units_", SyscallLogBpfComputeUnits::call)?; - result.register_function(b"sol_log_pubkey", SyscallLogPubkey::call)?; + result.register_function_hashed(*b"sol_log_", SyscallLog::call)?; + result.register_function_hashed(*b"sol_log_64_", SyscallLogU64::call)?; + result.register_function_hashed(*b"sol_log_compute_units_", SyscallLogBpfComputeUnits::call)?; + result.register_function_hashed(*b"sol_log_pubkey", SyscallLogPubkey::call)?; // Program defined addresses (PDA) - result.register_function( - b"sol_create_program_address", + result.register_function_hashed( + *b"sol_create_program_address", SyscallCreateProgramAddress::call, )?; - result.register_function( - b"sol_try_find_program_address", + result.register_function_hashed( + *b"sol_try_find_program_address", SyscallTryFindProgramAddress::call, )?; // Sha256 - result.register_function(b"sol_sha256", SyscallSha256::call)?; + result.register_function_hashed(*b"sol_sha256", SyscallSha256::call)?; // Keccak256 - result.register_function(b"sol_keccak256", SyscallKeccak256::call)?; + result.register_function_hashed(*b"sol_keccak256", SyscallKeccak256::call)?; // Secp256k1 Recover - result.register_function(b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?; + result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?; // Blake3 register_feature_gated_function!( result, blake3_syscall_enabled, - b"sol_blake3", + *b"sol_blake3", SyscallBlake3::call, )?; @@ -239,78 +236,78 @@ pub fn create_program_runtime_environment_v1<'a>( register_feature_gated_function!( result, curve25519_syscall_enabled, - b"sol_curve_validate_point", + *b"sol_curve_validate_point", SyscallCurvePointValidation::call, )?; register_feature_gated_function!( result, curve25519_syscall_enabled, - b"sol_curve_group_op", + *b"sol_curve_group_op", SyscallCurveGroupOps::call, )?; register_feature_gated_function!( result, curve25519_syscall_enabled, - b"sol_curve_multiscalar_mul", + *b"sol_curve_multiscalar_mul", SyscallCurveMultiscalarMultiplication::call, )?; // Sysvars - result.register_function(b"sol_get_clock_sysvar", SyscallGetClockSysvar::call)?; - result.register_function( - b"sol_get_epoch_schedule_sysvar", + result.register_function_hashed(*b"sol_get_clock_sysvar", SyscallGetClockSysvar::call)?; + result.register_function_hashed( + *b"sol_get_epoch_schedule_sysvar", SyscallGetEpochScheduleSysvar::call, )?; register_feature_gated_function!( result, !disable_fees_sysvar, - b"sol_get_fees_sysvar", + *b"sol_get_fees_sysvar", SyscallGetFeesSysvar::call, )?; - result.register_function(b"sol_get_rent_sysvar", SyscallGetRentSysvar::call)?; + result.register_function_hashed(*b"sol_get_rent_sysvar", SyscallGetRentSysvar::call)?; register_feature_gated_function!( result, last_restart_slot_syscall_enabled, - b"sol_get_last_restart_slot", + *b"sol_get_last_restart_slot", SyscallGetLastRestartSlotSysvar::call, )?; register_feature_gated_function!( result, epoch_rewards_syscall_enabled, - b"sol_get_epoch_rewards_sysvar", + *b"sol_get_epoch_rewards_sysvar", SyscallGetEpochRewardsSysvar::call, )?; // Memory ops - result.register_function(b"sol_memcpy_", SyscallMemcpy::call)?; - result.register_function(b"sol_memmove_", SyscallMemmove::call)?; - result.register_function(b"sol_memcmp_", SyscallMemcmp::call)?; - result.register_function(b"sol_memset_", SyscallMemset::call)?; + result.register_function_hashed(*b"sol_memcpy_", SyscallMemcpy::call)?; + result.register_function_hashed(*b"sol_memmove_", SyscallMemmove::call)?; + result.register_function_hashed(*b"sol_memcmp_", SyscallMemcmp::call)?; + result.register_function_hashed(*b"sol_memset_", SyscallMemset::call)?; // Processed sibling instructions - result.register_function( - b"sol_get_processed_sibling_instruction", + result.register_function_hashed( + *b"sol_get_processed_sibling_instruction", SyscallGetProcessedSiblingInstruction::call, )?; // Stack height - result.register_function(b"sol_get_stack_height", SyscallGetStackHeight::call)?; + result.register_function_hashed(*b"sol_get_stack_height", SyscallGetStackHeight::call)?; // Return data - result.register_function(b"sol_set_return_data", SyscallSetReturnData::call)?; - result.register_function(b"sol_get_return_data", SyscallGetReturnData::call)?; + result.register_function_hashed(*b"sol_set_return_data", SyscallSetReturnData::call)?; + result.register_function_hashed(*b"sol_get_return_data", SyscallGetReturnData::call)?; // Cross-program invocation - result.register_function(b"sol_invoke_signed_c", SyscallInvokeSignedC::call)?; - result.register_function(b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; + result.register_function_hashed(*b"sol_invoke_signed_c", SyscallInvokeSignedC::call)?; + result.register_function_hashed(*b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; // Memory allocator register_feature_gated_function!( result, !disable_deploy_of_alloc_free_syscall, - b"sol_alloc_free_", + *b"sol_alloc_free_", SyscallAllocFree::call, )?; @@ -318,7 +315,7 @@ pub fn create_program_runtime_environment_v1<'a>( register_feature_gated_function!( result, enable_alt_bn128_syscall, - b"sol_alt_bn128_group_op", + *b"sol_alt_bn128_group_op", SyscallAltBn128::call, )?; @@ -326,7 +323,7 @@ pub fn create_program_runtime_environment_v1<'a>( register_feature_gated_function!( result, enable_big_mod_exp_syscall, - b"sol_big_mod_exp", + *b"sol_big_mod_exp", SyscallBigModExp::call, )?; @@ -334,14 +331,14 @@ pub fn create_program_runtime_environment_v1<'a>( register_feature_gated_function!( result, enable_poseidon_syscall, - b"sol_poseidon", + *b"sol_poseidon", SyscallPoseidon::call, )?; // Log data - result.register_function(b"sol_log_data", SyscallLogData::call)?; + result.register_function_hashed(*b"sol_log_data", SyscallLogData::call)?; - Ok(result) + Ok(BuiltinProgram::new_loader(config, result)) } fn address_is_aligned(address: u64) -> bool { diff --git a/programs/loader-v4/Cargo.toml b/programs/loader-v4/Cargo.toml index 0ffdd87f6..a9f91dc8d 100644 --- a/programs/loader-v4/Cargo.toml +++ b/programs/loader-v4/Cargo.toml @@ -10,7 +10,6 @@ edition = { workspace = true } [dependencies] log = { workspace = true } -rand = { workspace = true } solana-measure = { workspace = true } solana-program-runtime = { workspace = true } solana-sdk = { workspace = true } diff --git a/programs/loader-v4/src/lib.rs b/programs/loader-v4/src/lib.rs index 5ebab0767..312c14f7a 100644 --- a/programs/loader-v4/src/lib.rs +++ b/programs/loader-v4/src/lib.rs @@ -1,5 +1,4 @@ use { - rand::Rng, solana_measure::measure::Measure, solana_program_runtime::{ compute_budget::ComputeBudget, @@ -14,13 +13,9 @@ use { solana_rbpf::{ aligned_memory::AlignedMemory, ebpf, - elf::Executable, + elf::{Executable, FunctionRegistry}, memory_region::{MemoryMapping, MemoryRegion}, - verifier::RequisiteVerifier, - vm::{ - BuiltinProgram, Config, ContextObject, EbpfVm, ProgramResult, - PROGRAM_ENVIRONMENT_KEY_SHIFT, - }, + vm::{BuiltinProgram, Config, ContextObject, EbpfVm, ProgramResult}, }, solana_sdk::{ entrypoint::{HEAP_LENGTH, SUCCESS}, @@ -86,10 +81,7 @@ pub fn create_program_runtime_environment_v2<'a>( reject_broken_elfs: true, noop_instruction_rate: 256, sanitize_user_provided_values: true, - runtime_environment_key: rand::thread_rng() - .gen::() - .checked_shr(PROGRAM_ENVIRONMENT_KEY_SHIFT) - .unwrap_or(0), + encrypt_runtime_environment: true, external_internal_function_hash_collision: true, reject_callx_r10: true, enable_sbpf_v1: false, @@ -99,7 +91,7 @@ pub fn create_program_runtime_environment_v2<'a>( aligned_memory_mapping: true, // Warning, do not use `Config::default()` so that configuration here is explicit. }; - BuiltinProgram::new_loader(config) + BuiltinProgram::new_loader(config, FunctionRegistry::default()) } fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 { @@ -116,7 +108,7 @@ fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 { /// Create the SBF virtual machine pub fn create_vm<'a, 'b>( invoke_context: &'a mut InvokeContext<'b>, - program: &'a Executable>, + program: &'a Executable>, ) -> Result>, Box> { let config = program.get_config(); let sbpf_version = program.get_sbpf_version(); @@ -152,13 +144,12 @@ pub fn create_vm<'a, 'b>( fn execute<'a, 'b: 'a>( invoke_context: &'a mut InvokeContext<'b>, - executable: &'a Executable>, + executable: &'a Executable>, ) -> Result<(), Box> { // We dropped the lifetime tracking in the Executor by setting it to 'static, // thus we need to reintroduce the correct lifetime of InvokeContext here again. - let executable = unsafe { - std::mem::transmute::<_, &'a Executable>>(executable) - }; + let executable = + unsafe { std::mem::transmute::<_, &'a Executable>>(executable) }; let log_collector = invoke_context.get_log_collector(); let stack_height = invoke_context.get_stack_height(); let transaction_context = &invoke_context.transaction_context; @@ -763,7 +754,11 @@ mod tests { let transaction_accounts = vec![ ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Deployed, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Deployed, + "relative_call", + ), ), ( authority_address, @@ -771,7 +766,11 @@ mod tests { ), ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Finalized, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Finalized, + "relative_call", + ), ), ( clock::id(), @@ -853,7 +852,11 @@ mod tests { let transaction_accounts = vec![ ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Retracted, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Retracted, + "relative_call", + ), ), ( authority_address, @@ -861,7 +864,11 @@ mod tests { ), ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Deployed, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Deployed, + "relative_call", + ), ), ( clock::id(), @@ -942,7 +949,11 @@ mod tests { let mut transaction_accounts = vec![ ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Retracted, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Retracted, + "relative_call", + ), ), ( authority_address, @@ -954,19 +965,23 @@ mod tests { ), ( Pubkey::new_unique(), - AccountSharedData::new(20000000, 0, &loader_v4::id()), + AccountSharedData::new(40000000, 0, &loader_v4::id()), ), ( Pubkey::new_unique(), load_program_account_from_elf( authority_address, LoaderV4Status::Retracted, - "rodata", + "rodata_section", ), ), ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Deployed, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Deployed, + "relative_call", + ), ), ( clock::id(), @@ -1194,7 +1209,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Retracted, - "rodata", + "rodata_section", ), ), ( @@ -1203,7 +1218,11 @@ mod tests { ), ( Pubkey::new_unique(), - load_program_account_from_elf(authority_address, LoaderV4Status::Retracted, "noop"), + load_program_account_from_elf( + authority_address, + LoaderV4Status::Retracted, + "relative_call", + ), ), ( Pubkey::new_unique(), @@ -1338,7 +1357,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Deployed, - "rodata", + "rodata_section", ), ), ( @@ -1354,7 +1373,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Retracted, - "rodata", + "rodata_section", ), ), (clock::id(), clock(1000)), @@ -1418,7 +1437,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Deployed, - "rodata", + "rodata_section", ), ), ( @@ -1426,7 +1445,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Retracted, - "rodata", + "rodata_section", ), ), ( @@ -1519,7 +1538,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Finalized, - "rodata", + "rodata_section", ), ), ( @@ -1535,7 +1554,7 @@ mod tests { load_program_account_from_elf( authority_address, LoaderV4Status::Retracted, - "rodata", + "rodata_section", ), ), ( diff --git a/programs/loader-v4/test_elfs/out/noop.so b/programs/loader-v4/test_elfs/out/noop.so deleted file mode 100755 index 7e74e2d7a78cde3e2a2a7dda703855bccd0eb505..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1768 zcmbVM!D6L3Gn%6f4n1R}}ayXW0^-@KdG_d53*OG{4HbSvfTyAhj) zADi9@0GsZXYvT8eTXj?(!%%!3BdpP)@)tknyhGhG#sf=T$5kJO3}&WlV0s*5*K|kW z36rlQUO7k=*ob?-#h86Q+$*roEy*)SfqGeTfkX0~1&U;yjNiW69v48`dk?Ok&-Y)5*1FCK$~>s9Lvlf8a+ zJLq)U!L=LVMtHNj`nOO0vimWwuax)QXfEE7)|vmG^@Mr?=#HVw407bxD*#6Jdd9P2a`PWo=2CY={W3G-_o=8lgC?+ zw(shA|BbqP_6|+=EsRR`&yT)?m=!qO?vBkZ@+nZ@s5?> z+TQVW=^%b4#y25vorRQku@Kc?-@@^rZCa8)0C9>LcZsp7(YV zL;3@AgsQWy7k>v@_PF%wQ=#gVzK&bavL@XV+|oYThWh^zulj`#v7p?FA$~D3GLrYm mdsh8A*N*WPwt$vBh~9$nj`E6r3P*289Pyozm#ZZFy8bs<*>lGL diff --git a/programs/loader-v4/test_elfs/out/relative_call.so b/programs/loader-v4/test_elfs/out/relative_call.so new file mode 100644 index 0000000000000000000000000000000000000000..9f24730e209597b7bb901191dc47dca8bd3a6887 GIT binary patch literal 5384 zcmeHLzi-n}5PnSx=9fe%5@JG@m>96^rb!HRD560^3Kb(|i5$nFp|KMj2Q})z#EP;o zFv35Ql|O@jfrT~P_ugFzrbtMPypvwOdw2KUJzx9=-`iIEab;~yiBy%NcP<%V-K7Qj zvT4vI*j1sb((gs(=$LbGZQ#dCfbD?ofbD?ofbD?ofbD?ofbD?ofbGD4-GSMLd3=We-_a-fBV4Hu z+!g0CDa+;Z^$lYxWBN#2EP{8zcY*l!uL znGKMRZ+$JqMQR)ea?^m)vj@_B_FrQA6-GWb@BSW8Ym+LvgwUVU(voCFJ{yk)S)tm4 z>?q0ayY2R#8`M4D+m@i;5job?H{H8cFP^ueE0{ViI}g}?ObD(#???D6mD70#wvhL< z&OEPIB*%sFdb2D_2eDQrv(#XbD=!|UDLs?&$XY~Q!ox|C8_l4~lVMa0-Xxtk8V`_n8g2BWMqDWdqOlPCS4c^HKCFziKJ{d%)etA$DH zEb7)z>NF)%t-0Os{a)nvlX@cxqLy0ee`oJt|KZaok8}h6@drJ|I(^@GFLS4PDSvsc zg!=<-mE#bPd@`pRvt7@;NEbf8{<;j_ZQKe`Paq3sLw{a;2qMX_G;)e=Fi!PbK}mI&mWLYddHy}zB0f3 VCre$4eeehVZJt|xmO#cb{|AeCfu;Ze literal 0 HcmV?d00001 diff --git a/programs/loader-v4/test_elfs/out/rodata.so b/programs/loader-v4/test_elfs/out/rodata.so deleted file mode 100755 index 9b8a8b8ed028086865511620166e94704ff3d223..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1904 zcmb_cO=}cE5Uu^tM5CAwl%ODU^OIo{4TxS6jDoUy$jN{p)TB!)FCUZsayAhj)jkz3z2?qIKMzVogtmkqBN z5`G>}6Ziv*=f1vLpK<>}Y-d?2<-G+axS+TsRavzCGJlthFYn3XaelgzjpxN9G*6xRmaD$_>5t_REnEInd9aL*&-EkcEH7k#}zgc-iJ%ji2c+L2~@)%~F z{Y=6%X-8QkVLOkbey>$H!@Tb>OC{WkKZMpKmm#5sXVF{5?l4Q8 z=TO|_VQc24z1iM`9GLZ@-ITe!O8mw~6VA`=|66qMrK-lw-{zl<%I%caJfcP47DTy{YZj zbeeE|{s)M6Et2nn>vMv2b&!q^I;T{6z$x};yL!`dMStlL3v KoF>)x^?v|FRc+S* diff --git a/programs/loader-v4/test_elfs/out/rodata_section.so b/programs/loader-v4/test_elfs/out/rodata_section.so new file mode 100644 index 0000000000000000000000000000000000000000..8868f7e63d7e85b0963ee207dc796f3c0b2fdd51 GIT binary patch literal 5424 zcmeHL&ubGw6rTLhrnaEAAUWwAgW!_IrVTx%wH1VI@gSmJ!e+DDpxKno3eBm1h5v^K z5B@3rH#`Ym;`?^rx5OnE@g&TH+3(Gp@4Ywkm|2*)J`JANYc)e@n2oXr>p%xCcM8P{ z3{2lN<-27z4LG+jbPu0G7!7FEMkEhoO=(vBFit+OB@IHX`rWACjc~vxzJ!wqk$!ct z-Imr-zmDkeBYqVfLM-zZX7_a!a20SBa20SBa20SBa20SBa20SBa20SB_^&JQO)kM! zR`630_u+-!kH6@u9xFan#GM^-zW~!#KYbqHb=&OfxP~*omdhDT$N|A!9Kw71R?#(W z#r#b{^p?iIqxNmZ2a10S$iJhrfNmKePO@}yIh!OIEjf$t0Kp{r7^jCe2u`fu^Sa(% zNn5KRcGLV=RtF!6p=RoNUT_%y4T$wd`5u8Td6pJhfu;yHoX1f%nI&G>?~SAP`}<_xNBw9tj>mo+`=@55p2L&3=SOERp5+Vr#}8_T#{GkE z=yT&)=qtkd(zGE8_;?S3SZU~6-KbT5wSQN*$lZ_z=}3b=-<9}&RPJApM0gIczp>Yu zpZlNhSzVAt;E%Y>&vRkLhTQb$`Dp2Z::from_elf( - &elf, - program_runtime_environment.clone(), - ) - .unwrap(); + let _ = Executable::::from_elf(&elf, program_runtime_environment.clone()) + .unwrap(); }); } @@ -124,19 +118,16 @@ fn bench_program_alu(bencher: &mut Bencher) { true, false, ); - let executable = Executable::::from_elf( - &elf, - Arc::new(program_runtime_environment.unwrap()), - ) - .unwrap(); + let mut executable = + Executable::::from_elf(&elf, Arc::new(program_runtime_environment.unwrap())) + .unwrap(); - let mut verified_executable = - Executable::::verified(executable).unwrap(); + executable.verify::().unwrap(); - verified_executable.jit_compile().unwrap(); + executable.jit_compile().unwrap(); create_vm!( vm, - &verified_executable, + &executable, vec![MemoryRegion::new_writable(&mut inner_iter, MM_INPUT_START)], vec![], &mut invoke_context, @@ -146,7 +137,7 @@ fn bench_program_alu(bencher: &mut Bencher) { println!("Interpreted:"); vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - let (instructions, result) = vm.execute_program(&verified_executable, true); + let (instructions, result) = vm.execute_program(&executable, true); assert_eq!(SUCCESS, result.unwrap()); assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter)); assert_eq!( @@ -157,7 +148,7 @@ fn bench_program_alu(bencher: &mut Bencher) { bencher.iter(|| { vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - vm.execute_program(&verified_executable, true).1.unwrap(); + vm.execute_program(&executable, true).1.unwrap(); }); let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap(); println!(" {:?} instructions", instructions); @@ -168,10 +159,7 @@ fn bench_program_alu(bencher: &mut Bencher) { println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips); println!("JIT to native:"); - assert_eq!( - SUCCESS, - vm.execute_program(&verified_executable, false).1.unwrap() - ); + assert_eq!(SUCCESS, vm.execute_program(&executable, false).1.unwrap()); assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter)); assert_eq!( ARMSTRONG_EXPECTED, @@ -181,7 +169,7 @@ fn bench_program_alu(bencher: &mut Bencher) { bencher.iter(|| { vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - vm.execute_program(&verified_executable, false).1.unwrap(); + vm.execute_program(&executable, false).1.unwrap(); }); let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap(); println!(" {:?} instructions", instructions); @@ -243,14 +231,11 @@ fn bench_create_vm(bencher: &mut Bencher) { true, false, ); - let executable = Executable::::from_elf( - &elf, - Arc::new(program_runtime_environment.unwrap()), - ) - .unwrap(); + let executable = + Executable::::from_elf(&elf, Arc::new(program_runtime_environment.unwrap())) + .unwrap(); - let verified_executable = - Executable::::verified(executable).unwrap(); + executable.verify::().unwrap(); // Serialize account data let (_serialized, regions, account_lengths) = serialize_parameters( @@ -267,7 +252,7 @@ fn bench_create_vm(bencher: &mut Bencher) { bencher.iter(|| { create_vm!( vm, - &verified_executable, + &executable, clone_regions(®ions), account_lengths.clone(), &mut invoke_context, @@ -305,18 +290,15 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { true, false, ); - let executable = Executable::::from_elf( - &elf, - Arc::new(program_runtime_environment.unwrap()), - ) - .unwrap(); + let executable = + Executable::::from_elf(&elf, Arc::new(program_runtime_environment.unwrap())) + .unwrap(); - let verified_executable = - Executable::::verified(executable).unwrap(); + executable.verify::().unwrap(); create_vm!( vm, - &verified_executable, + &executable, regions, account_lengths, &mut invoke_context, @@ -324,7 +306,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let mut vm = vm.unwrap(); let mut measure = Measure::start("tune"); - let (instructions, _result) = vm.execute_program(&verified_executable, true); + let (instructions, _result) = vm.execute_program(&executable, true); measure.stop(); assert_eq!(