From a8b5a32b50740b6a1918692fae8581d2400cb961 Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 5 Jan 2021 13:53:41 -0800 Subject: [PATCH] Gate cpi program account passing (#14443) --- programs/bpf_loader/src/syscalls.rs | 36 ++++++++++++++++++++--------- runtime/src/message_processor.rs | 2 +- sdk/src/feature_set.rs | 5 ++++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 857ee62556..039da3b897 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -19,7 +19,7 @@ use solana_sdk::{ feature_set::{ limit_cpi_loader_invoke, pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled, sol_log_compute_units_syscall, - try_find_program_address_syscall_enabled, + try_find_program_address_syscall_enabled, use_loaded_program_accounts, }, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, @@ -851,6 +851,7 @@ trait SyscallInvokeSigned<'a> { ) -> Result>; fn translate_accounts( &self, + skip_program: bool, account_keys: &[Pubkey], program_account_index: usize, account_infos_addr: u64, @@ -913,6 +914,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn translate_accounts( &self, + skip_program: bool, account_keys: &[Pubkey], program_account_index: usize, account_infos_addr: u64, @@ -933,7 +935,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { let mut accounts = Vec::with_capacity(account_keys.len()); let mut refs = Vec::with_capacity(account_keys.len()); 'root: for (i, account_key) in account_keys.iter().enumerate() { - if i == program_account_index { + if skip_program && i == program_account_index { // Don't look for caller passed executable, runtime already has it continue 'root; } @@ -1199,6 +1201,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_accounts( &self, + skip_program: bool, account_keys: &[Pubkey], program_account_index: usize, account_infos_addr: u64, @@ -1214,7 +1217,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { let mut accounts = Vec::with_capacity(account_keys.len()); let mut refs = Vec::with_capacity(account_keys.len()); 'root: for (i, account_key) in account_keys.iter().enumerate() { - if i == program_account_index { + if skip_program && i == program_account_index { // Don't look for caller passed executable, runtime already has it continue 'root; } @@ -1400,6 +1403,9 @@ fn call<'a>( .get_compute_meter() .consume(invoke_context.get_bpf_compute_budget().invoke_units)?; + let use_loaded_program_accounts = + invoke_context.is_feature_active(&use_loaded_program_accounts::id()); + // Translate and verify caller's data let instruction = syscall.translate_instruction( @@ -1422,15 +1428,16 @@ fn call<'a>( .get_callers_keyed_accounts() .iter() .collect::>(); - let (message, callee_program_id, program_id_index) = + let (message, callee_program_id, callee_program_id_index) = MessageProcessor::create_message(&instruction, &keyed_account_refs, &signers) .map_err(SyscallError::InstructionError)?; if invoke_context.is_feature_active(&limit_cpi_loader_invoke::id()) { check_authorized_program(&callee_program_id)?; } let (mut accounts, mut account_refs) = syscall.translate_accounts( + use_loaded_program_accounts, &message.account_keys, - program_id_index, + callee_program_id_index, account_infos_addr, account_infos_len, memory_mapping, @@ -1440,12 +1447,21 @@ fn call<'a>( invoke_context.record_instruction(&instruction); - let program_account = - invoke_context - .get_account(&callee_program_id) + let program_account = if use_loaded_program_accounts { + let program_account = invoke_context.get_account(&callee_program_id).ok_or( + SyscallError::InstructionError(InstructionError::MissingAccount), + )?; + accounts.insert(callee_program_id_index, Rc::new(program_account.clone())); + account_refs.insert(callee_program_id_index, None); + program_account + } else { + (**accounts + .get(callee_program_id_index) .ok_or(SyscallError::InstructionError( InstructionError::MissingAccount, - ))?; + ))?) + .clone() + }; if !program_account.borrow().executable { return Err(SyscallError::InstructionError(InstructionError::AccountNotExecutable).into()); } @@ -1470,8 +1486,6 @@ fn call<'a>( } else { None }; - accounts.insert(program_id_index, Rc::new(program_account.clone())); - account_refs.insert(program_id_index, None); let mut executable_accounts = vec![(callee_program_id, program_account)]; if let Some(programdata) = programdata_executable { executable_accounts.push(programdata); diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 497eaa9d7f..71d3669954 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -546,7 +546,7 @@ impl MessageProcessor { let _ = keyed_accounts .iter() .find_map(|keyed_account| { - if &instruction.program_id == keyed_account.unsigned_key() { + if &program_id == keyed_account.unsigned_key() { Some(keyed_account) } else { None diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index ba324cd314..45e81f180b 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -126,6 +126,10 @@ pub mod limit_cpi_loader_invoke { solana_sdk::declare_id!("xGbcW7EEC7zMRJ6LaJCob65EJxKryWjwM4rv8f57SRM"); } +pub mod use_loaded_program_accounts { + solana_sdk::declare_id!("FLjgLeg1PJkZimQCVa5sVFtaq6VmSDPw3NvH8iQ3nyHn"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -159,6 +163,7 @@ lazy_static! { (stake_program_v3::id(), "solana_stake_program v3"), (max_cpi_instruction_size_ipv6_mtu::id(), "Max cross-program invocation size 1280"), (limit_cpi_loader_invoke::id(), "Loader not authorized via CPI"), + (use_loaded_program_accounts::id(), "Use loaded program accounts"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()