diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 573c264894bbcd..20b32ab18fee5c 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -12,7 +12,7 @@ use solana_rbpf::{ #[allow(deprecated)] use solana_sdk::sysvar::fees::Fees; use solana_sdk::{ - account::{Account, AccountSharedData, ReadableAccount}, + account::{AccountSharedData, ReadableAccount}, account_info::AccountInfo, blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock::Clock, @@ -27,7 +27,9 @@ use solana_sdk::{ hash::{Hasher, HASH_BYTES}, ic_msg, instruction::{AccountMeta, Instruction, InstructionError}, - keccak, native_loader, + keccak, + message::Message, + native_loader, process_instruction::{self, stable_log, ComputeMeter, InvokeContext, Logger}, program::MAX_RETURN_DATA, pubkey::{Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN}, @@ -1645,8 +1647,7 @@ trait SyscallInvokeSigned<'a> { ) -> Result>; fn translate_accounts( &self, - account_keys: &[Pubkey], - program_account_index: usize, + message: &Message, account_infos_addr: u64, account_infos_len: u64, memory_mapping: &MemoryMapping, @@ -1719,8 +1720,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn translate_accounts( &self, - account_keys: &[Pubkey], - program_account_index: usize, + message: &Message, account_infos_addr: u64, account_infos_len: u64, memory_mapping: &MemoryMapping, @@ -1829,8 +1829,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { }; get_translated_accounts( - account_keys, - program_account_index, + message, &account_info_keys, account_infos, invoke_context, @@ -2042,8 +2041,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_accounts( &self, - account_keys: &[Pubkey], - program_account_index: usize, + message: &Message, account_infos_addr: u64, account_infos_len: u64, memory_mapping: &MemoryMapping, @@ -2134,8 +2132,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { }; get_translated_accounts( - account_keys, - program_account_index, + message, &account_info_keys, account_infos, invoke_context, @@ -2223,8 +2220,7 @@ impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { } fn get_translated_accounts<'a, T, F>( - account_keys: &[Pubkey], - program_account_index: usize, + message: &Message, account_info_keys: &[&Pubkey], account_infos: &[T], invoke_context: &mut dyn InvokeContext, @@ -2233,11 +2229,15 @@ fn get_translated_accounts<'a, T, F>( where F: Fn(&T, &mut dyn InvokeContext) -> Result, EbpfError>, { - let mut accounts = Vec::with_capacity(account_keys.len()); - let mut refs = Vec::with_capacity(account_keys.len()); - for (i, ref account_key) in account_keys.iter().enumerate() { - let (_account_index, account) = - invoke_context.get_account(account_key).ok_or_else(|| { + let demote_program_write_locks = + invoke_context.is_feature_active(&demote_program_write_locks::id()); + let mut accounts = Vec::with_capacity(message.account_keys.len()); + let mut refs = Vec::with_capacity(message.account_keys.len()); + for (i, account_key) in message.account_keys.iter().enumerate() { + let ((_account_index, account), account_ref_index) = invoke_context + .get_account(account_key) + .zip(account_info_keys.iter().position(|key| *key == account_key)) + .ok_or_else(|| { ic_msg!( invoke_context, "Instruction references an unknown account {}", @@ -2245,41 +2245,28 @@ where ); SyscallError::InstructionError(InstructionError::MissingAccount) })?; + let account_ref = do_translate(&account_infos[account_ref_index], invoke_context)?; - if i == program_account_index || account.borrow().executable() { - // Use the known account - accounts.push((**account_key, account)); - refs.push(None); - } else if let Some(account_info) = - account_info_keys - .iter() - .zip(account_infos) - .find_map(|(key, account_info)| { - if key == account_key { - Some(account_info) - } else { - None - } - }) { - let account_ref = do_translate(account_info, invoke_context)?; - let account = Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: *account_ref.lamports, - data: account_ref.data.to_vec(), - executable: account_ref.executable, - owner: *account_ref.owner, - rent_epoch: account_ref.rent_epoch, - }))); - accounts.push((**account_key, account)); - refs.push(Some(account_ref)); - } else { - ic_msg!( - invoke_context, - "Instruction references an unknown account {}", - account_key - ); - return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into()); + let mut account = account.borrow_mut(); + use solana_sdk::account::WritableAccount; + if !account.executable() { + account.copy_into_owner_from_slice(account_ref.owner.as_ref()); + account.set_data_from_slice(account_ref.data); + account.set_lamports(*account_ref.lamports); + account.set_executable(account_ref.executable); + account.set_rent_epoch(account_ref.rent_epoch); + } } + accounts.push((*account_key, account)); + + refs.push( + if !message.is_writable(i, demote_program_write_locks) || account_ref.executable { + None + } else { + Some(account_ref) + }, + ); } Ok((accounts, refs)) @@ -2374,8 +2361,7 @@ fn call<'a>( invoke_context.is_feature_active(&close_upgradeable_program_accounts::id()), )?; let (accounts, account_refs) = syscall.translate_accounts( - &message.account_keys, - message.instructions[0].program_id_index as usize, + &message, account_infos_addr, account_infos_len, memory_mapping, @@ -2396,52 +2382,46 @@ fn call<'a>( .map_err(SyscallError::InstructionError)?; // Copy results back to caller - let demote_program_write_locks = - invoke_context.is_feature_active(&demote_program_write_locks::id()); - for (i, ((_key, account), account_ref)) in accounts.iter().zip(account_refs).enumerate() { + for ((_key, account), account_ref) in accounts.iter().zip(account_refs) { let account = account.borrow(); if let Some(mut account_ref) = account_ref { - if message.is_writable(i, demote_program_write_locks) && !account.executable() { - *account_ref.lamports = account.lamports(); - *account_ref.owner = *account.owner(); - if account_ref.data.len() != account.data().len() { - if !account_ref.data.is_empty() { - // Only support for `CreateAccount` at this time. - // Need a way to limit total realloc size across multiple CPI calls - ic_msg!( - invoke_context, - "Inner instructions do not support realloc, only SystemProgram::CreateAccount", - ); - return Err(SyscallError::InstructionError( - InstructionError::InvalidRealloc, - ) - .into()); - } - if account.data().len() > account_ref.data.len() + MAX_PERMITTED_DATA_INCREASE { - ic_msg!( - invoke_context, - "SystemProgram::CreateAccount data size limited to {} in inner instructions", - MAX_PERMITTED_DATA_INCREASE - ); - return Err(SyscallError::InstructionError( - InstructionError::InvalidRealloc, - ) - .into()); - } - account_ref.data = translate_slice_mut::( - memory_mapping, - account_ref.vm_data_addr, - account.data().len() as u64, - &bpf_loader_deprecated::id(), // Don't care since it is byte aligned - true, - )?; - *account_ref.ref_to_len_in_vm = account.data().len() as u64; - *account_ref.serialized_len_ptr = account.data().len() as u64; + *account_ref.lamports = account.lamports(); + *account_ref.owner = *account.owner(); + if account_ref.data.len() != account.data().len() { + if !account_ref.data.is_empty() { + // Only support for `CreateAccount` at this time. + // Need a way to limit total realloc size across multiple CPI calls + ic_msg!( + invoke_context, + "Inner instructions do not support realloc, only SystemProgram::CreateAccount", + ); + return Err( + SyscallError::InstructionError(InstructionError::InvalidRealloc).into(), + ); } - account_ref - .data - .copy_from_slice(&account.data()[0..account_ref.data.len()]); + if account.data().len() > account_ref.data.len() + MAX_PERMITTED_DATA_INCREASE { + ic_msg!( + invoke_context, + "SystemProgram::CreateAccount data size limited to {} in inner instructions", + MAX_PERMITTED_DATA_INCREASE + ); + return Err( + SyscallError::InstructionError(InstructionError::InvalidRealloc).into(), + ); + } + account_ref.data = translate_slice_mut::( + memory_mapping, + account_ref.vm_data_addr, + account.data().len() as u64, + &bpf_loader_deprecated::id(), // Don't care since it is byte aligned + true, + )?; + *account_ref.ref_to_len_in_vm = account.data().len() as u64; + *account_ref.serialized_len_ptr = account.data().len() as u64; } + account_ref + .data + .copy_from_slice(&account.data()[0..account_ref.data.len()]); } }