From 3a6cae59307bce0e1f67a8adf9484098e6230586 Mon Sep 17 00:00:00 2001 From: HaoranYi Date: Tue, 21 Nov 2023 15:21:33 +0000 Subject: [PATCH] use PROGRAM_OWNER to check executable on account --- runtime/src/accounts/mod.rs | 44 ++++++++++++++++++------------------- sdk/src/account.rs | 15 ++++++++++++- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/runtime/src/accounts/mod.rs b/runtime/src/accounts/mod.rs index 01df5c9bc01390..820c19c7b3fbb0 100644 --- a/runtime/src/accounts/mod.rs +++ b/runtime/src/accounts/mod.rs @@ -24,7 +24,10 @@ use { loaded_programs::LoadedProgramsForTxBatch, }, solana_sdk::{ - account::{Account, AccountSharedData, ReadableAccount, WritableAccount}, + account::{ + is_builtin, is_builtin_or_executable, is_executable, Account, AccountSharedData, + ReadableAccount, WritableAccount, + }, account_utils::StateMut, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, feature_set::{ @@ -288,25 +291,23 @@ fn load_transaction_accounts( return Err(TransactionError::InvalidWritableAccount); } - if account.executable() { - // The upgradeable loader requires the derived ProgramData account - if let Ok(UpgradeableLoaderState::Program { - programdata_address, - }) = account.state() + // The upgradeable loader requires the derived ProgramData account + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = account.state() + { + if accounts_db + .load_with_fixed_root(ancestors, &programdata_address) + .is_none() { - if accounts_db - .load_with_fixed_root(ancestors, &programdata_address) - .is_none() - { - error_counters.account_not_found += 1; - return Err(TransactionError::ProgramAccountNotFound); - } - } else { - error_counters.invalid_program_for_execution += 1; - return Err(TransactionError::InvalidProgramForExecution); + error_counters.account_not_found += 1; + return Err(TransactionError::ProgramAccountNotFound); } + } else { + error_counters.invalid_program_for_execution += 1; + return Err(TransactionError::InvalidProgramForExecution); } - } else if account.executable() && message.is_writable(i) { + } else if is_builtin_or_executable(&account) && message.is_writable(i) { error_counters.invalid_writable_account += 1; return Err(TransactionError::InvalidWritableAccount); } @@ -355,15 +356,16 @@ fn load_transaction_accounts( let (program_id, program_account) = accounts .get(program_index) .ok_or(TransactionError::ProgramAccountNotFound)?; - let account_found = accounts_found.get(program_index).unwrap_or(&true); if native_loader::check_id(program_id) { return Ok(account_indices); } + + let account_found = accounts_found.get(program_index).unwrap_or(&true); if !account_found { error_counters.account_not_found += 1; return Err(TransactionError::ProgramAccountNotFound); } - if !program_account.executable() { + if !is_builtin_or_executable(program_account) { error_counters.invalid_program_for_execution += 1; return Err(TransactionError::InvalidProgramForExecution); } @@ -384,9 +386,7 @@ fn load_transaction_accounts( if let Some((owner_account, _)) = accounts_db.load_with_fixed_root(ancestors, owner_id) { - if !native_loader::check_id(owner_account.owner()) - || !owner_account.executable() - { + if !is_builtin(&owner_account) || !is_executable(&owner_account) { error_counters.invalid_program_for_execution += 1; return Err(TransactionError::InvalidProgramForExecution); } diff --git a/sdk/src/account.rs b/sdk/src/account.rs index d94d7dc2c6b6e5..ff2a17588b646a 100644 --- a/sdk/src/account.rs +++ b/sdk/src/account.rs @@ -7,7 +7,7 @@ use { bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock::{Epoch, INITIAL_RENT_EPOCH}, lamports::LamportsError, - loader_v4, + loader_v4, native_loader, pubkey::Pubkey, }, serde::{ @@ -764,6 +764,19 @@ pub const PROGRAM_OWNERS: &[Pubkey] = &[ loader_v4::id(), ]; +/// Check if user program is executable. +pub fn is_executable(account: &AccountSharedData) -> bool { + PROGRAM_OWNERS.iter().any(|v| account.owner() == v) +} + +pub fn is_builtin(account: &AccountSharedData) -> bool { + native_loader::check_id(account.owner()) +} + +pub fn is_builtin_or_executable(account: &AccountSharedData) -> bool { + is_builtin(account) || is_executable(account) +} + #[cfg(test)] pub mod tests { use super::*;