Deprecate account meta executable read/update in bpf loaders (#34194)

* use PROGRAM_OWNER + program data for account executable

mock account data with executable_meta in precompiled program and update
test_bank_hash_consistency test

pr: return const slice and add comments

pr: use ReadableAccount

use const to get rid of magic number

add featuregate disable_bpf_loader_instructions to disable bpf loader management instructions, and deprecate_executable_meta_update_in_bpf_loader to deprecate executable flag update in bpf loader

deprecate usage of executable in Account

fix a test

fix sbp bench

fix sbf program tests

add feature gate to account and borrowed account apis

fix tests

more test fixes

* restore bpf_loader v2 tests

---------

Co-authored-by: HaoranYi <haoran.yi@solana.com>
This commit is contained in:
HaoranYi 2024-01-03 15:11:48 -06:00 committed by GitHub
parent 1d93732a60
commit 5a3a10e847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 596 additions and 84 deletions

View File

@ -44,7 +44,7 @@ use {
},
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
solana_sdk::{
account::Account,
account::{is_executable, Account},
account_utils::StateMut,
bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
@ -1036,6 +1036,15 @@ fn get_default_program_keypair(program_location: &Option<String>) -> Keypair {
program_keypair
}
fn is_account_executable(account: &Account) -> bool {
if account.owner == bpf_loader_deprecated::id() || account.owner == bpf_loader::id() {
account.executable
} else {
let feature_set = FeatureSet::all_enabled();
is_executable(account, &feature_set)
}
}
/// Deploy program using upgradeable loader. It also can process program upgrades
#[allow(clippy::too_many_arguments)]
fn process_program_deploy(
@ -1092,7 +1101,7 @@ fn process_program_deploy(
.into());
}
if !account.executable {
if !is_account_executable(&account) {
// Continue an initial deploy
true
} else if let Ok(UpgradeableLoaderState::Program {
@ -2444,7 +2453,7 @@ fn complete_partial_program_init(
) -> Result<(Vec<Instruction>, u64), Box<dyn std::error::Error>> {
let mut instructions: Vec<Instruction> = vec![];
let mut balance_needed = 0;
if account.executable {
if is_account_executable(account) {
return Err("Buffer account is already executable".into());
}
if account.owner != *loader_id && !system_program::check_id(&account.owner) {

View File

@ -14,9 +14,11 @@ use {
solana_rpc_client::rpc_client::RpcClient,
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
solana_sdk::{
account::is_executable,
account_utils::StateMut,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
commitment_config::CommitmentConfig,
feature_set::FeatureSet,
pubkey::Pubkey,
signature::{Keypair, NullSigner, Signer},
},
@ -100,7 +102,8 @@ fn test_cli_program_deploy_non_upgradeable() {
let account0 = rpc_client.get_account(&program_id).unwrap();
assert_eq!(account0.lamports, minimum_balance_for_program);
assert_eq!(account0.owner, bpf_loader_upgradeable::id());
assert!(account0.executable);
assert!(is_executable(&account0, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_id.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@ -109,7 +112,10 @@ fn test_cli_program_deploy_non_upgradeable() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]
@ -137,7 +143,7 @@ fn test_cli_program_deploy_non_upgradeable() {
.unwrap();
assert_eq!(account1.lamports, minimum_balance_for_program);
assert_eq!(account1.owner, bpf_loader_upgradeable::id());
assert!(account1.executable);
assert!(is_executable(&account1, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) = Pubkey::find_program_address(
&[custom_address_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
@ -148,7 +154,10 @@ fn test_cli_program_deploy_non_upgradeable() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]
@ -376,7 +385,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert!(is_executable(&program_account, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
@ -387,7 +396,10 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]
@ -421,7 +433,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert!(is_executable(&program_account, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@ -430,7 +442,10 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]
@ -455,7 +470,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert!(is_executable(&program_account, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@ -464,7 +479,10 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]
@ -511,7 +529,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert!(is_executable(&program_account, &FeatureSet::all_enabled()));
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@ -520,7 +538,10 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert!(!is_executable(
&programdata_account,
&FeatureSet::all_enabled()
));
assert_eq!(
programdata_account.data[UpgradeableLoaderState::size_of_programdata_metadata()..],
program_data[..]

View File

@ -962,8 +962,8 @@ mod tests {
let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
let readonly_account = AccountSharedData::new(168, 1, &solana_sdk::pubkey::new_rand());
let loader_account = AccountSharedData::new(0, 0, &native_loader::id());
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
let loader_account = AccountSharedData::new(0, 1, &native_loader::id());
let mut program_account = AccountSharedData::new(1, 1, &native_loader::id());
program_account.set_executable(true);
let transaction_accounts = vec![
(solana_sdk::pubkey::new_rand(), owned_account),
@ -990,7 +990,7 @@ mod tests {
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
callee_program_id,
Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)),
Arc::new(LoadedProgram::new_builtin(0, 1, MockBuiltin::vm)),
);
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;

View File

@ -34,7 +34,8 @@ use {
clock::Slot,
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{
bpf_account_data_direct_mapping, enable_bpf_loader_extend_program_ix,
bpf_account_data_direct_mapping, deprecate_executable_meta_update_in_bpf_loader,
disable_bpf_loader_instructions, enable_bpf_loader_extend_program_ix,
enable_bpf_loader_set_authority_checked_ix, native_programs_consume_cu,
remove_bpf_loader_incorrect_program_id, FeatureSet,
},
@ -785,7 +786,15 @@ fn process_loader_upgradeable_instruction(
},
&invoke_context.feature_set,
)?;
program.set_executable(true)?;
// Skip writing true to executable meta after bpf program deployment when
// `deprecate_executable_meta_update_in_bpf_loader` feature is activated.
if !invoke_context
.feature_set
.is_active(&deprecate_executable_meta_update_in_bpf_loader::id())
{
program.set_executable(true)?;
}
drop(program);
ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id);
@ -1469,6 +1478,20 @@ fn process_loader_instruction(invoke_context: &mut InvokeContext) -> Result<(),
);
return Err(InstructionError::IncorrectProgramId);
}
// Return `UnsupportedProgramId` error for bpf_loader when
// `disable_bpf_loader_instruction` feature is activated.
if invoke_context
.feature_set
.is_active(&disable_bpf_loader_instructions::id())
{
ic_msg!(
invoke_context,
"BPF loader management instructions are no longer supported"
);
return Err(InstructionError::UnsupportedProgramId);
}
let is_program_signer = program.is_signer();
match limited_deserialize(instruction_data)? {
LoaderInstruction::Write { offset, bytes } => {
@ -1493,6 +1516,13 @@ fn process_loader_instruction(invoke_context: &mut InvokeContext) -> Result<(),
{},
program.get_data(),
);
// `deprecate_executable_meta_update_in_bpf_loader` feature doesn't
// apply to bpf_loader v2. Instead, the deployment by bpf_loader
// will be deprecated by its own feature
// `disable_bpf_loader_instructions`. Before we activate
// deprecate_executable_meta_update_in_bpf_loader, we should
// activate `disable_bpf_loader_instructions` first.
program.set_executable(true)?;
ic_msg!(invoke_context, "Finalized account {:?}", program.get_key());
}
@ -1779,6 +1809,10 @@ mod tests {
expected_result,
Entrypoint::vm,
|invoke_context| {
let mut features = FeatureSet::all_enabled();
features.deactivate(&disable_bpf_loader_instructions::id());
features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
invoke_context.feature_set = Arc::new(features);
test_utils::load_all_invoked_programs(invoke_context);
},
|_invoke_context| {},
@ -1998,6 +2032,10 @@ mod tests {
Err(InstructionError::ProgramFailedToComplete),
Entrypoint::vm,
|invoke_context| {
let mut features = FeatureSet::all_enabled();
features.deactivate(&disable_bpf_loader_instructions::id());
features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
invoke_context.feature_set = Arc::new(features);
invoke_context.mock_set_remaining(0);
test_utils::load_all_invoked_programs(invoke_context);
},
@ -2543,7 +2581,12 @@ mod tests {
instruction_accounts,
expected_result,
Entrypoint::vm,
|_invoke_context| {},
|invoke_context| {
let mut features = FeatureSet::all_enabled();
features.deactivate(&disable_bpf_loader_instructions::id());
features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
invoke_context.feature_set = Arc::new(features);
},
|_invoke_context| {},
)
}

View File

@ -938,7 +938,7 @@ mod tests {
assert_eq!(account.lamports(), account_info.lamports());
assert_eq!(account.data(), &account_info.data.borrow()[..]);
assert_eq!(account.owner(), account_info.owner);
assert_eq!(account.executable(), account_info.executable);
assert!(account_info.executable);
assert_eq!(account.rent_epoch(), account_info.rent_epoch);
assert_eq!(
@ -1023,7 +1023,7 @@ mod tests {
assert_eq!(account.lamports(), account_info.lamports());
assert_eq!(account.data(), &account_info.data.borrow()[..]);
assert_eq!(account.owner(), account_info.owner);
assert_eq!(account.executable(), account_info.executable);
assert!(account_info.executable);
assert_eq!(account.rent_epoch(), account_info.rent_epoch);
}

View File

@ -466,6 +466,7 @@ pub fn process_instruction_retract(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let authority_address = instruction_context
.get_index_of_instruction_account_in_transaction(1)
.and_then(|index| transaction_context.get_key_of_account_at_index(index))?;

View File

@ -34,7 +34,7 @@ use {
bpf_loader,
client::SyncClient,
entrypoint::SUCCESS,
feature_set::FeatureSet,
feature_set::{self, FeatureSet},
instruction::{AccountMeta, Instruction},
message::Message,
native_loader,
@ -185,10 +185,21 @@ fn bench_program_alu(bencher: &mut Bencher) {
#[bench]
fn bench_program_execute_noop(bencher: &mut Bencher) {
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and benched.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let bank = Bank::new_for_benches(&genesis_config);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank.clone());

View File

@ -323,11 +323,21 @@ fn test_program_sbf_sanity() {
println!("Test program: {:?}", program.0);
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
@ -403,10 +413,21 @@ fn test_sol_alloc_free_no_longer_deployable() {
let program_address = program_keypair.pubkey();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
// Populate loader account with elf that depends on _sol_alloc_free syscall
@ -516,10 +537,21 @@ fn test_program_sbf_duplicate_accounts() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
let (bank, program_id) = load_program_and_advance_slot(
@ -620,10 +652,21 @@ fn test_program_sbf_error_handling() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let (_, program_id) = load_program_and_advance_slot(
@ -726,10 +769,21 @@ fn test_return_data_and_log_data_syscall() {
for program in programs.iter() {
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -794,10 +848,21 @@ fn test_program_sbf_invoke_sanity() {
println!("Test program: {:?}", program);
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -1191,10 +1256,20 @@ fn test_program_sbf_invoke_sanity() {
#[cfg(feature = "sbf_rust")]
fn test_program_sbf_program_id_spoofing() {
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -1242,10 +1317,20 @@ fn test_program_sbf_program_id_spoofing() {
#[cfg(feature = "sbf_rust")]
fn test_program_sbf_caller_has_access_to_cpi_program() {
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -1280,10 +1365,20 @@ fn test_program_sbf_ro_modify() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -1335,10 +1430,20 @@ fn test_program_sbf_call_depth() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let (_, program_id) = load_program_and_advance_slot(
@ -1369,10 +1474,20 @@ fn test_program_sbf_compute_budget() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let (_, program_id) = load_program_and_advance_slot(
@ -1497,10 +1612,20 @@ fn test_program_sbf_instruction_introspection() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50_000);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -1555,10 +1680,20 @@ fn test_program_sbf_test_use_latest_executor() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let panic_id = load_program(
@ -2247,10 +2382,21 @@ fn test_program_sbf_invoke_upgradeable_via_cpi() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let invoke_and_return = load_program(
@ -2376,7 +2522,6 @@ fn test_program_sbf_disguised_as_sbf_loader() {
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new_for_tests(&genesis_config);
// disable native_programs_consume_cu feature to allow test program
// not consume units.
@ -2386,6 +2531,8 @@ fn test_program_sbf_disguised_as_sbf_loader() {
bank.deactivate_feature(
&solana_sdk::feature_set::remove_bpf_loader_incorrect_program_id::id(),
);
bank.deactivate_feature(&feature_set::disable_bpf_loader_instructions::id());
bank.deactivate_feature(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let bank = bank.wrap_with_bank_forks_for_tests().0;
let bank_client = BankClient::new_shared(bank);
@ -2406,10 +2553,21 @@ fn test_program_reads_from_program_account() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
@ -2433,10 +2591,21 @@ fn test_program_sbf_c_dup() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let account_address = Pubkey::new_unique();
@ -2468,10 +2637,21 @@ fn test_program_sbf_upgrade_via_cpi() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
let invoke_and_return = load_program(
@ -2578,10 +2758,21 @@ fn test_program_sbf_set_upgrade_authority_via_cpi() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank);
@ -2793,10 +2984,21 @@ fn test_program_sbf_finalize() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -2841,10 +3043,21 @@ fn test_program_sbf_ro_account_modify() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -2903,10 +3116,21 @@ fn test_program_sbf_realloc() {
const START_BALANCE: u64 = 100_000_000_000;
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(1_000_000_000_000);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let mint_pubkey = mint_keypair.pubkey();
let signer = &[&mint_keypair];
for direct_mapping in [false, true] {
@ -3242,6 +3466,17 @@ fn test_program_sbf_realloc_invoke() {
..
} = create_genesis_config(1_000_000_000_000);
genesis_config.rent = Rent::default();
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let mint_pubkey = mint_keypair.pubkey();
let signer = &[&mint_keypair];
@ -3757,10 +3992,21 @@ fn test_program_sbf_processed_inner_instruction() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
let mut bank_client = BankClient::new_shared(bank.clone());
@ -3837,12 +4083,22 @@ fn test_program_fees() {
mint_keypair,
..
} = create_genesis_config(500_000_000);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
genesis_config.fee_rate_governor = FeeRateGovernor::new(congestion_multiplier, 0);
let mut bank = Bank::new_for_tests(&genesis_config);
let fee_structure =
FeeStructure::new(0.000005, 0.0, vec![(200, 0.0000005), (1400000, 0.000005)]);
bank.fee_structure = fee_structure.clone();
bank.feature_set = Arc::new(FeatureSet::all_enabled());
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank);
@ -3905,12 +4161,22 @@ fn test_program_fees() {
#[cfg(feature = "sbf_rust")]
fn test_get_minimum_delegation() {
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
let mut bank = Bank::new_for_tests(&genesis_config);
bank.feature_set = Arc::new(FeatureSet::all_enabled());
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let bank = Bank::new_for_tests(&genesis_config);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank.clone());
@ -3977,11 +4243,16 @@ fn test_cpi_account_ownership_writability() {
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
let mut bank = Bank::new_for_tests(&genesis_config);
let mut feature_set = FeatureSet::all_enabled();
if !direct_mapping {
feature_set.deactivate(&feature_set::bpf_account_data_direct_mapping::id());
}
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
feature_set.deactivate(&feature_set::disable_bpf_loader_instructions::id());
feature_set.deactivate(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
bank.feature_set = Arc::new(feature_set);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank);
@ -4164,6 +4435,11 @@ fn test_cpi_account_data_updates() {
if !direct_mapping {
feature_set.deactivate(&feature_set::bpf_account_data_direct_mapping::id());
}
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
feature_set.deactivate(&feature_set::disable_bpf_loader_instructions::id());
feature_set.deactivate(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
bank.feature_set = Arc::new(feature_set);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank);
@ -4307,11 +4583,18 @@ fn test_cpi_deprecated_loader_realloc() {
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
let mut bank = Bank::new_for_tests(&genesis_config);
let mut feature_set = FeatureSet::all_enabled();
if !direct_mapping {
feature_set.deactivate(&feature_set::bpf_account_data_direct_mapping::id());
}
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
feature_set.deactivate(&feature_set::disable_bpf_loader_instructions::id());
feature_set.deactivate(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
bank.feature_set = Arc::new(feature_set);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
@ -4416,13 +4699,22 @@ fn test_cpi_change_account_data_memory_allocation() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let mut bank = Bank::new_for_tests(&genesis_config);
let feature_set = FeatureSet::all_enabled();
bank.feature_set = Arc::new(feature_set);
declare_process_instruction!(MockBuiltin, 42, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
@ -4502,13 +4794,22 @@ fn test_cpi_invalid_account_info_pointers() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
let mut bank = Bank::new_for_tests(&genesis_config);
let feature_set = FeatureSet::all_enabled();
bank.feature_set = Arc::new(feature_set);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
let bank = Bank::new_for_tests(&genesis_config);
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let mut bank_client = BankClient::new_shared(bank);
@ -4565,11 +4866,21 @@ fn test_deny_executable_write() {
solana_logger::setup();
let GenesisConfigInfo {
genesis_config,
mut genesis_config,
mint_keypair,
..
} = create_genesis_config(100_123_456_789);
// deactivate `disable_bpf_loader_instructions` feature so that the program
// can be loaded, finalized and tested.
genesis_config
.accounts
.remove(&feature_set::disable_bpf_loader_instructions::id());
genesis_config
.accounts
.remove(&feature_set::deprecate_executable_meta_update_in_bpf_loader::id());
for direct_mapping in [false, true] {
let mut bank = Bank::new_for_tests(&genesis_config);
let feature_set = Arc::make_mut(&mut bank.feature_set);

View File

@ -24,7 +24,10 @@ use {
loaded_programs::LoadedProgramsForTxBatch,
},
solana_sdk::{
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
account::{
create_executable_meta, is_builtin, is_executable, Account, AccountSharedData,
ReadableAccount, WritableAccount,
},
account_utils::StateMut,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
feature_set::{
@ -279,7 +282,7 @@ fn load_transaction_accounts(
return Err(TransactionError::InvalidWritableAccount);
}
if account.executable() {
if is_builtin(&account) || is_executable(&account, feature_set) {
// The upgradeable loader requires the derived ProgramData account
if let Ok(UpgradeableLoaderState::Program {
programdata_address,
@ -297,9 +300,13 @@ fn load_transaction_accounts(
return Err(TransactionError::InvalidProgramForExecution);
}
}
} else if account.executable() && message.is_writable(i) {
error_counters.invalid_writable_account += 1;
return Err(TransactionError::InvalidWritableAccount);
} else {
if (is_builtin(&account) || is_executable(&account, feature_set))
&& message.is_writable(i)
{
error_counters.invalid_writable_account += 1;
return Err(TransactionError::InvalidWritableAccount);
}
}
}
@ -346,15 +353,17 @@ 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(program_account) || is_executable(program_account, feature_set)) {
error_counters.invalid_program_for_execution += 1;
return Err(TransactionError::InvalidProgramForExecution);
}
@ -376,7 +385,8 @@ fn load_transaction_accounts(
accounts_db.load_with_fixed_root(ancestors, owner_id)
{
if !native_loader::check_id(owner_account.owner())
|| !owner_account.executable()
|| !(is_builtin(&owner_account)
|| is_executable(&owner_account, feature_set))
{
error_counters.invalid_program_for_execution += 1;
return Err(TransactionError::InvalidProgramForExecution);
@ -442,6 +452,7 @@ fn account_shared_data_from_program(
.ok_or(TransactionError::AccountNotFound)?;
program_account.set_owner(**program_owner);
program_account.set_executable(true);
program_account.set_data_from_slice(create_executable_meta(program_owner));
Ok(program_account)
}
@ -908,7 +919,8 @@ mod tests {
accounts.push((key0, account));
let mut account = AccountSharedData::new(40, 1, &Pubkey::default());
account.set_executable(true);
account.set_owner(bpf_loader_upgradeable::id());
account.set_data(create_executable_meta(account.owner()).to_vec());
accounts.push((key1, account));
let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
@ -942,7 +954,7 @@ mod tests {
let account = AccountSharedData::new(1, 0, &Pubkey::default());
accounts.push((key0, account));
let account = AccountSharedData::new(40, 1, &native_loader::id());
let account = AccountSharedData::new(40, 0, &native_loader::id());
accounts.push((key1, account));
let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
@ -971,7 +983,7 @@ mod tests {
let keypair = Keypair::new();
let key0 = keypair.pubkey();
let key1 = Pubkey::from([5u8; 32]);
let key1 = bpf_loader_upgradeable::id();
let key2 = Pubkey::from([6u8; 32]);
let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
@ -988,6 +1000,7 @@ mod tests {
account.set_executable(true);
account.set_rent_epoch(1);
account.set_owner(key1);
account.set_data(create_executable_meta(account.owner()).to_vec());
accounts.push((key2, account));
let instructions = vec![

View File

@ -126,9 +126,9 @@ use {
},
solana_sdk::{
account::{
create_account_shared_data_with_fields as create_account, from_account, Account,
AccountSharedData, InheritableAccountFields, ReadableAccount, WritableAccount,
PROGRAM_OWNERS,
create_account_shared_data_with_fields as create_account, create_executable_meta,
from_account, Account, AccountSharedData, InheritableAccountFields, ReadableAccount,
WritableAccount, PROGRAM_OWNERS,
},
account_utils::StateMut,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
@ -3882,7 +3882,6 @@ impl Bank {
fn add_precompiled_account_with_owner(&self, program_id: &Pubkey, owner: Pubkey) {
if let Some(account) = self.get_account_with_fixed_root(program_id) {
if account.executable() {
// The account is already executable, that's all we need
return;
} else {
// malicious account is pre-occupying at program_id
@ -3898,10 +3897,13 @@ impl Bank {
// Add a bogus executable account, which will be loaded and ignored.
let (lamports, rent_epoch) = self.inherit_specially_retained_account_fields(&None);
// Mock account_data with executable_meta so that the account is executable.
let account_data = create_executable_meta(&owner);
let account = AccountSharedData::from(Account {
lamports,
owner,
data: vec![],
data: account_data.to_vec(),
executable: true,
rent_epoch,
});

View File

@ -1025,6 +1025,8 @@ fn test_rent_exempt_executable_account() {
let account_balance = 1;
let mut account = AccountSharedData::new(account_balance, 0, &solana_sdk::pubkey::new_rand());
account.set_executable(true);
account.set_owner(bpf_loader_upgradeable::id());
account.set_data(create_executable_meta(account.owner()).to_vec());
bank.store_account(&account_pubkey, &account);
let transfer_lamports = 1;
@ -6458,25 +6460,25 @@ fn test_bank_hash_consistency() {
if bank.slot == 0 {
assert_eq!(
bank.hash().to_string(),
"3KE2bigpBiiMLGYNqmWkgbrQGSqMt5ccG6ED87CFCVpt"
"trdzvRDTAXAqo1i2GX4JfK9ReixV1NYNG7DRaVq43Do",
);
}
if bank.slot == 32 {
assert_eq!(
bank.hash().to_string(),
"FpNDsd21HXznXf6tRpMNiWhFyhZ4aCCECQm3gL4jGV22"
"2rdj8QEnDnBSyMv81rCmncss4UERACyXXB3pEvkep8eS",
);
}
if bank.slot == 64 {
assert_eq!(
bank.hash().to_string(),
"7gDCoXPfFtKPALi212akhhQHEuLdAqyf7DE3yUN4bR2p"
"7g3ofXVQB3reFt9ki8zLA8S4w1GdmEWsWuWrwkPN3SSv"
);
}
if bank.slot == 128 {
assert_eq!(
bank.hash().to_string(),
"6FREbeHdTNYnEXg4zobL2mqGfevukg75frkQJqKpYnk4"
"4uX1AZFbqwjwWBACWbAW3V8rjbWH4N3ZRTbNysSLAzj2"
);
break;
}

View File

@ -6,8 +6,9 @@ use {
crate::{
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
clock::{Epoch, INITIAL_RENT_EPOCH},
feature_set::{deprecate_executable_meta_update_in_bpf_loader, FeatureSet},
lamports::LamportsError,
loader_v4,
loader_v4, native_loader,
pubkey::Pubkey,
},
serde::{
@ -39,6 +40,9 @@ pub struct Account {
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
/// this account's data contains a loaded program (and is now read-only)
///
/// When feature `deprecate_executable_meta_update_in_bpf_loader` is active,
/// `executable` is deprecated, please use `fn is_executable(&account)` instead.
pub executable: bool,
/// the epoch at which this account will next owe rent
pub rent_epoch: Epoch,
@ -764,6 +768,91 @@ pub const PROGRAM_OWNERS: &[Pubkey] = &[
loader_v4::id(),
];
const LOADER_V4_STATUS_BYTE_OFFSET: usize = 40;
/// Create executable account meta data based on account's `owner`.
///
/// This function is only used for testing and an optimization during
/// transaction loading.
///
/// When the program account is already present in the program cache, we don't
/// need to load the full account data during transaction loading. Instead, all
/// we need is a minimal executable account meta data, which is what this
/// function returns.
pub fn create_executable_meta(owner: &Pubkey) -> &[u8] {
// For upgradable program account, only `UpgradeableLoaderState::Program`
// variant (i.e. discriminant = 2) should *executable*, which means the
// discriminant for the enum at byte offset 0 in account data is 2.
const EXECUTABLE_META_FOR_BPF_LOADER_UPGRADABLE: [u8; 1] = [2];
// For loader v4 program, when LoaderV4Status (byte_offset = 40 in account
// data) is set, the program is executable.
const fn get_executable_meta_for_loader_v4() -> [u8; 41] {
let mut v = [0; LOADER_V4_STATUS_BYTE_OFFSET + 1];
v[LOADER_V4_STATUS_BYTE_OFFSET] = 1;
v
}
const EXECUTABLE_META_FOR_LOADER_V4: [u8; LOADER_V4_STATUS_BYTE_OFFSET + 1] =
get_executable_meta_for_loader_v4();
// For other owners, simple returns a 1 byte array would make it executable.
const DEFAULT_EXECUTABLE_META: [u8; 1] = [1];
if bpf_loader_upgradeable::check_id(owner) {
&EXECUTABLE_META_FOR_BPF_LOADER_UPGRADABLE
} else if loader_v4::check_id(owner) {
&EXECUTABLE_META_FOR_LOADER_V4
} else {
&DEFAULT_EXECUTABLE_META
}
}
/// Return true if the account program is executable.
pub fn is_executable(account: &impl ReadableAccount, feature_set: &FeatureSet) -> bool {
if !feature_set.is_active(&deprecate_executable_meta_update_in_bpf_loader::id()) {
account.executable()
} else {
// First, check if the account is empty. Empty accounts are not executable.
if account.data().is_empty() {
return false;
}
// bpf_loader/bpf_loader_deprecated still relies on `executable` on the
// program account. When the program account is finalized, the loader will
// mark `executable` flag on the account. We can't emulate `executable` for
// these two loaders. However, when `deprecate_executable` is true, we
// should have already disabled the deployment of bpf_loader and
// bpf_loader_deprecated. Therefore, we can safely assume that all those
// programs are `executable`.
if bpf_loader::check_id(account.owner()) || bpf_loader_deprecated::check_id(account.owner())
{
return true;
}
if bpf_loader_upgradeable::check_id(account.owner()) {
// For upgradable program account, only
// `UpgradeableLoaderState::Program` variant (i.e. discriminant = 2) is
// *executable*.
return account.data()[0] == 2;
}
if loader_v4::check_id(account.owner()) {
// LoaderV4Status (byte_offset = 40)
// return account.data()[LOADER_V4_STATUS_BYTE_OFFSET] != 0;
return false; // TODO: return false for now
}
false
}
}
/// Return true if the account program is a builtin program. Note that for
/// builtin program, even when its account data is empty, it is still be
/// executable, such as vote program etc.
pub fn is_builtin(account: &impl ReadableAccount) -> bool {
native_loader::check_id(account.owner()) && !account.data().is_empty()
}
#[cfg(test)]
pub mod tests {
use super::*;

View File

@ -752,6 +752,14 @@ pub mod merkle_conflict_duplicate_proofs {
solana_sdk::declare_id!("mrkPjRg79B2oK2ZLgd7S3AfEJaX9B6gAF3H9aEykRUS");
}
pub mod disable_bpf_loader_instructions {
solana_sdk::declare_id!("7WeS1vfPRgeeoXArLh7879YcB9mgE9ktjPDtajXeWfXn");
}
pub mod deprecate_executable_meta_update_in_bpf_loader {
solana_sdk::declare_id!("k6uR1J9VtKJnTukBV2Eo15BEy434MBg8bT6hHQgmU8v");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -935,6 +943,8 @@ lazy_static! {
(consume_blockstore_duplicate_proofs::id(), "consume duplicate proofs from blockstore in consensus #34372"),
(index_erasure_conflict_duplicate_proofs::id(), "generate duplicate proofs for index and erasure conflicts #34360"),
(merkle_conflict_duplicate_proofs::id(), "generate duplicate proofs for merkle root conflicts #34270"),
(disable_bpf_loader_instructions::id(), "disable bpf loader management instructions #34194"),
(deprecate_executable_meta_update_in_bpf_loader::id(), "deprecate executable meta flag update in bpf loader #34194"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()

View File

@ -17,7 +17,7 @@ use {
};
use {
crate::{
account::{AccountSharedData, ReadableAccount},
account::{is_builtin, is_executable, AccountSharedData, ReadableAccount},
feature_set::FeatureSet,
instruction::InstructionError,
pubkey::Pubkey,
@ -1040,8 +1040,8 @@ impl<'a> BorrowedAccount<'a> {
/// Returns whether this account is executable (transaction wide)
#[inline]
pub fn is_executable(&self, _feature_set: &FeatureSet) -> bool {
self.account.executable()
pub fn is_executable(&self, feature_set: &FeatureSet) -> bool {
is_builtin(&*self.account) || is_executable(&*self.account, feature_set)
}
/// Configures whether this account is executable (transaction wide)