diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index 8780b874e2e..19d2dc9b041 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -23,7 +23,7 @@ use { runtime_config::RuntimeConfig, }, solana_sdk::{ - account::{Account, AccountSharedData, ReadableAccount}, + account::{Account, AccountSharedData}, account_info::AccountInfo, clock::Slot, entrypoint::{deserialize, ProgramResult, SUCCESS}, @@ -291,23 +291,12 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { } _ => {} } - if borrowed_account.is_executable() != account_info.executable { - borrowed_account - .set_executable(account_info.executable) - .unwrap(); - } // Change the owner at the end so that we are allowed to change the lamports and data before if borrowed_account.get_owner() != account_info.owner { borrowed_account .set_owner(account_info.owner.as_ref()) .unwrap(); } - drop(borrowed_account); - let account = transaction_context - .get_account_at_index(instruction_account.index_in_transaction) - .unwrap() - .borrow(); - assert_eq!(account.rent_epoch(), account_info.rent_epoch); if instruction_account.is_writable { account_indices.push((instruction_account.index_in_caller, account_info_index)); } diff --git a/programs/bpf/c/src/invoke/invoke.c b/programs/bpf/c/src/invoke/invoke.c index cfc8075cef0..f37ff8a1d21 100644 --- a/programs/bpf/c/src/invoke/invoke.c +++ b/programs/bpf/c/src/invoke/invoke.c @@ -25,13 +25,12 @@ static const uint8_t TEST_PRIVILEGE_DEESCALATION_ESCALATION_SIGNER = 12; static const uint8_t TEST_PRIVILEGE_DEESCALATION_ESCALATION_WRITABLE = 13; static const uint8_t TEST_WRITABLE_DEESCALATION_WRITABLE = 14; static const uint8_t TEST_NESTED_INVOKE_TOO_DEEP = 15; -static const uint8_t TEST_EXECUTABLE_LAMPORTS = 16; -static const uint8_t TEST_CALL_PRECOMPILE = 17; -static const uint8_t ADD_LAMPORTS = 18; -static const uint8_t TEST_RETURN_DATA_TOO_LARGE = 19; -static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER = 20; -static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE = 21; -static const uint8_t TEST_MAX_ACCOUNT_INFOS_EXCEEDED = 22; +static const uint8_t TEST_CALL_PRECOMPILE = 16; +static const uint8_t ADD_LAMPORTS = 17; +static const uint8_t TEST_RETURN_DATA_TOO_LARGE = 18; +static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER = 19; +static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE = 20; +static const uint8_t TEST_MAX_ACCOUNT_INFOS_EXCEEDED = 21; static const int MINT_INDEX = 0; static const int ARGUMENT_INDEX = 1; @@ -320,6 +319,21 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert(accounts[ARGUMENT_INDEX].data[i] == 0); } } + + sol_log("Test that is_executable and rent_epoch are ignored"); + { + accounts[INVOKED_ARGUMENT_INDEX].executable = true; + accounts[INVOKED_ARGUMENT_INDEX].rent_epoch += 1; + SolAccountMeta arguments[] = { + {accounts[INVOKED_ARGUMENT_INDEX].key, true, false}}; + uint8_t data[] = {RETURN_OK}; + const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, + arguments, SOL_ARRAY_SIZE(arguments), + data, SOL_ARRAY_SIZE(data)}; + + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); + } break; } case TEST_PRIVILEGE_ESCALATION_SIGNER: { @@ -593,25 +607,6 @@ extern uint64_t entrypoint(const uint8_t *input) { do_nested_invokes(5, accounts, params.ka_num); break; } - case TEST_EXECUTABLE_LAMPORTS: { - sol_log("Test executable lamports"); - accounts[ARGUMENT_INDEX].executable = true; - *accounts[ARGUMENT_INDEX].lamports -= 1; - *accounts[DERIVED_KEY1_INDEX].lamports +=1; - SolAccountMeta arguments[] = { - {accounts[ARGUMENT_INDEX].key, true, false}, - {accounts[DERIVED_KEY1_INDEX].key, true, false}, - }; - uint8_t data[] = {ADD_LAMPORTS, 0, 0, 0}; - SolPubkey program_id; - sol_memcpy(&program_id, params.program_id, sizeof(SolPubkey)); - const SolInstruction instruction = {&program_id, - arguments, SOL_ARRAY_SIZE(arguments), - data, SOL_ARRAY_SIZE(data)}; - sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)); - *accounts[ARGUMENT_INDEX].lamports += 1; - break; - } case TEST_CALL_PRECOMPILE: { sol_log("Test calling precompile from cpi"); SolAccountMeta arguments[] = {}; diff --git a/programs/bpf/rust/invoke/src/instructions.rs b/programs/bpf/rust/invoke/src/instructions.rs index 08a1fa32164..464ec392816 100644 --- a/programs/bpf/rust/invoke/src/instructions.rs +++ b/programs/bpf/rust/invoke/src/instructions.rs @@ -15,13 +15,12 @@ pub const TEST_PRIVILEGE_DEESCALATION_ESCALATION_SIGNER: u8 = 12; pub const TEST_PRIVILEGE_DEESCALATION_ESCALATION_WRITABLE: u8 = 13; pub const TEST_WRITABLE_DEESCALATION_WRITABLE: u8 = 14; pub const TEST_NESTED_INVOKE_TOO_DEEP: u8 = 15; -pub const TEST_EXECUTABLE_LAMPORTS: u8 = 16; -pub const TEST_CALL_PRECOMPILE: u8 = 17; -pub const ADD_LAMPORTS: u8 = 18; -pub const TEST_RETURN_DATA_TOO_LARGE: u8 = 19; -pub const TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER: u8 = 20; -pub const TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE: u8 = 21; -pub const TEST_MAX_ACCOUNT_INFOS_EXCEEDED: u8 = 22; +pub const TEST_CALL_PRECOMPILE: u8 = 16; +pub const ADD_LAMPORTS: u8 = 17; +pub const TEST_RETURN_DATA_TOO_LARGE: u8 = 18; +pub const TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER: u8 = 19; +pub const TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE: u8 = 20; +pub const TEST_MAX_ACCOUNT_INFOS_EXCEEDED: u8 = 21; pub const MINT_INDEX: usize = 0; pub const ARGUMENT_INDEX: usize = 1; diff --git a/programs/bpf/rust/invoke/src/processor.rs b/programs/bpf/rust/invoke/src/processor.rs index c3c92cf2f1c..c519b7353b2 100644 --- a/programs/bpf/rust/invoke/src/processor.rs +++ b/programs/bpf/rust/invoke/src/processor.rs @@ -639,38 +639,6 @@ fn process_instruction( TEST_NESTED_INVOKE_TOO_DEEP => { let _ = do_nested_invokes(5, accounts); } - TEST_EXECUTABLE_LAMPORTS => { - msg!("Test executable lamports"); - let mut accounts = accounts.to_vec(); - - // set account to executable and subtract lamports - accounts[ARGUMENT_INDEX].executable = true; - { - let mut lamports = (*accounts[ARGUMENT_INDEX].lamports).borrow_mut(); - **lamports = (*lamports).saturating_sub(1); - } - // add lamports to dest account - { - let mut lamports = (*accounts[DERIVED_KEY1_INDEX].lamports).borrow_mut(); - **lamports = (*lamports).saturating_add(1); - } - - let instruction = create_instruction( - *program_id, - &[ - (accounts[ARGUMENT_INDEX].key, true, false), - (accounts[DERIVED_KEY1_INDEX].key, true, false), - ], - vec![ADD_LAMPORTS, 0, 0, 0], - ); - let _ = invoke(&instruction, &accounts); - - // reset executable account - { - let mut lamports = (*accounts[ARGUMENT_INDEX].lamports).borrow_mut(); - **lamports = (*lamports).saturating_add(1); - } - } TEST_CALL_PRECOMPILE => { msg!("Test calling precompiled program from cpi"); let instruction = diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 444579cc2f8..1461c43e315 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1102,6 +1102,7 @@ fn test_program_bpf_invoke_sanity() { invoked_program_id.clone(), invoked_program_id.clone(), invoked_program_id.clone(), + invoked_program_id.clone(), ], Languages::Rust => vec![ system_program::id(), @@ -1310,13 +1311,6 @@ fn test_program_bpf_invoke_sanity() { None, ); - do_invoke_failure_test_local( - TEST_EXECUTABLE_LAMPORTS, - TransactionError::InstructionError(0, InstructionError::ExecutableLamportChange), - &[invoke_program_id.clone()], - None, - ); - do_invoke_failure_test_local( TEST_CALL_PRECOMPILE, TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete), diff --git a/programs/bpf_loader/src/syscalls/cpi.rs b/programs/bpf_loader/src/syscalls/cpi.rs index f569812565d..d465c506288 100644 --- a/programs/bpf_loader/src/syscalls/cpi.rs +++ b/programs/bpf_loader/src/syscalls/cpi.rs @@ -619,6 +619,9 @@ where .get_current_instruction_context() .map_err(SyscallError::InstructionError)?; let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1)); + let is_disable_cpi_setting_executable_and_rent_epoch_active = invoke_context + .feature_set + .is_active(&disable_cpi_setting_executable_and_rent_epoch::id()); let program_account_index = program_indices .last() @@ -680,7 +683,9 @@ where } _ => {} } - if callee_account.is_executable() != caller_account.executable { + if !is_disable_cpi_setting_executable_and_rent_epoch_active + && callee_account.is_executable() != caller_account.executable + { callee_account .set_executable(caller_account.executable) .map_err(SyscallError::InstructionError)?; @@ -696,7 +701,9 @@ where .transaction_context .get_account_at_index(instruction_account.index_in_transaction) .map_err(SyscallError::InstructionError)?; - if callee_account.borrow().rent_epoch() != caller_account.rent_epoch { + if !is_disable_cpi_setting_executable_and_rent_epoch_active + && callee_account.borrow().rent_epoch() != caller_account.rent_epoch + { if invoke_context .feature_set .is_active(&enable_early_verification_of_account_modifications::id()) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 651b714396e..f1aeba3b80f 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -34,10 +34,10 @@ use { entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS}, feature_set::{ self, blake3_syscall_enabled, check_physical_overlapping, check_slice_translation_size, - curve25519_syscall_enabled, disable_fees_sysvar, - enable_early_verification_of_account_modifications, libsecp256k1_0_5_upgrade_enabled, - limit_secp256k1_recovery_id, prevent_calling_precompiles_as_programs, - syscall_saturated_math, + curve25519_syscall_enabled, disable_cpi_setting_executable_and_rent_epoch, + disable_fees_sysvar, enable_early_verification_of_account_modifications, + libsecp256k1_0_5_upgrade_enabled, limit_secp256k1_recovery_id, + prevent_calling_precompiles_as_programs, syscall_saturated_math, }, hash::{Hasher, HASH_BYTES}, instruction::{ diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 0d85d3e3ab1..210b147b33e 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -496,6 +496,10 @@ pub mod incremental_snapshot_only_incremental_hash_calculation { solana_sdk::declare_id!("25vqsfjk7Nv1prsQJmA4Xu1bN61s8LXCBGUPp8Rfy1UF"); } +pub mod disable_cpi_setting_executable_and_rent_epoch { + solana_sdk::declare_id!("B9cdB55u4jQsDNsdTK525yE9dmSc5Ga7YBaBrDFvEhM9"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -614,6 +618,7 @@ lazy_static! { (sign_repair_requests::id(), "sign repair requests #26834"), (concurrent_replay_of_forks::id(), "Allow slots from different forks to be replayed concurrently #26465"), (incremental_snapshot_only_incremental_hash_calculation::id(), "only hash accounts in incremental snapshot during incremental snapshot creation #26799"), + (disable_cpi_setting_executable_and_rent_epoch::id(), "disable setting is_executable and_rent_epoch in CPI #26987"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()