diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 5ba8b26e086c69..2ce6bd72e5bf2d 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1586,8 +1586,8 @@ mod tests { solana_rbpf::vm::ContextObject, solana_sdk::{ account::{ - create_account_shared_data_for_test as create_account_for_test, AccountSharedData, - ReadableAccount, WritableAccount, + create_account_shared_data_for_test as create_account_for_test, is_executable, + AccountSharedData, ReadableAccount, WritableAccount, }, account_utils::StateMut, clock::Clock, @@ -1650,6 +1650,16 @@ mod tests { program_account } + #[test] + fn test_bpf_loader_is_executable() { + let loader_id = bpf_loader::id(); + let mut program_account = + load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so"); + program_account.set_executable(false); + let feature_set = FeatureSet::all_enabled(); + assert!(is_executable(&program_account, &feature_set)); + } + #[test] fn test_bpf_loader_invoke_main() { let loader_id = bpf_loader::id(); diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index d4cbd09642f47c..e7bb6b07b90ef4 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -809,7 +809,7 @@ mod tests { solana_sdk::pubkey::new_rand(), AccountSharedData::from(Account { lamports: 1, - data: vec![1u8, 2, 3, 4, 5], + data: vec![0x7f, 0x45, 0x4c, 0x46, 5], owner: bpf_loader::id(), executable: false, rent_epoch: 100, @@ -819,7 +819,7 @@ mod tests { solana_sdk::pubkey::new_rand(), AccountSharedData::from(Account { lamports: 2, - data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], + data: vec![0x7f, 0x45, 0x4c, 0x46, 15, 16, 17, 18, 19], owner: bpf_loader::id(), executable: true, rent_epoch: 200, @@ -839,7 +839,7 @@ mod tests { solana_sdk::pubkey::new_rand(), AccountSharedData::from(Account { lamports: 4, - data: vec![1u8, 2, 3, 4, 5], + data: vec![0x7f, 0x45, 0x4c, 0x46, 5], owner: bpf_loader::id(), executable: false, rent_epoch: 100, @@ -849,7 +849,7 @@ mod tests { solana_sdk::pubkey::new_rand(), AccountSharedData::from(Account { lamports: 5, - data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], + data: vec![0x7f, 0x45, 0x4c, 0x46, 15, 16, 17, 18, 19], owner: bpf_loader::id(), executable: true, rent_epoch: 200, diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index a01e9c19de6a39..109505537bf6d1 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -6498,25 +6498,25 @@ fn test_bank_hash_consistency() { if bank.slot == 0 { assert_eq!( bank.hash().to_string(), - "3VqF5pMe3XABLqzUaYw2UVXfAokMJgMkrdfvneFQkHbB", + "AAv6wZeKSMRPxSx2XqmbAbzs4k4WwSSipaRi9vJuzjy7", ); } if bank.slot == 32 { assert_eq!( bank.hash().to_string(), - "B8GsaBJ9aJrQcbhTTfgNVuV4uwb4v8nKT86HUjDLvNgk", + "9vDtVTtYDiePfYwzh548PRa5wLvfjqjvNQqiDiuXBch8", ); } if bank.slot == 64 { assert_eq!( bank.hash().to_string(), - "Eg9VRE3zUwarxWyHXhitX9wLkg1vfNeiVqVQxSif6qEC" + "GFNhkBoCY72V3HxHXpPv8RGtQkMT9tAmavpX3MW3fymP" ); } if bank.slot == 128 { assert_eq!( bank.hash().to_string(), - "5rLmK24zyxdeb8aLn5LDEnHLDQmxRd5gWZDVJGgsFX1c" + "CXyWuUgVB8r9M555iRZ5iYnrwHy3tQx1spfCsgsbQSoF" ); break; } diff --git a/sdk/src/account.rs b/sdk/src/account.rs index 96cdd5b90ce99b..47830a90e3695a 100644 --- a/sdk/src/account.rs +++ b/sdk/src/account.rs @@ -794,8 +794,8 @@ pub fn create_executable_meta(owner: &Pubkey) -> &[u8] { 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]; + // For other owners, simple returns a 4 byte array of elf header to make it executable. + const DEFAULT_EXECUTABLE_META: [u8; 4] = [0x7f, 0x45, 0x4c, 0x46]; if bpf_loader_upgradeable::check_id(owner) { &EXECUTABLE_META_FOR_BPF_LOADER_UPGRADABLE @@ -821,11 +821,14 @@ pub fn is_executable(account: &impl ReadableAccount, feature_set: &FeatureSet) - // 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`. + // bpf_loader_deprecated. if bpf_loader::check_id(account.owner()) || bpf_loader_deprecated::check_id(account.owner()) { - return true; + const ELF_HEADER: [u8; 4] = [0x7f, 0x45, 0x4c, 0x46]; + if account.data().len() < 4 { + return false; + } + return account.data()[0..4] == ELF_HEADER; } if bpf_loader_upgradeable::check_id(account.owner()) { @@ -870,6 +873,21 @@ pub mod tests { (account1, account2) } + #[test] + fn test_is_executable() { + let feature_set = FeatureSet::all_enabled(); + + let key = Pubkey::new_unique(); + let (mut account1, mut account2) = make_two_accounts(&key); + + account1.set_owner(bpf_loader::id()); + assert!(!is_executable(&account1, &feature_set)); + + account2.set_owner(bpf_loader::id()); + account2.set_data_from_slice(&[0x7f, 0x45, 0x4c, 0x46]); + assert!(is_executable(&account2, &feature_set)); + } + #[test] fn test_account_data_copy_as_slice() { let key = Pubkey::new_unique();