diff --git a/programs/bpf/rust/noop/src/lib.rs b/programs/bpf/rust/noop/src/lib.rs index b014dfed9d..e2db6da550 100644 --- a/programs/bpf/rust/noop/src/lib.rs +++ b/programs/bpf/rust/noop/src/lib.rs @@ -4,7 +4,8 @@ extern crate solana_sdk; use solana_sdk::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, info, log::*, pubkey::Pubkey, + account_info::AccountInfo, bpf_loader, entrypoint, entrypoint::ProgramResult, info, log::*, + pubkey::Pubkey, }; #[derive(Debug, PartialEq)] @@ -28,6 +29,8 @@ fn process_instruction( info!("Program identifier:"); program_id.log(); + assert!(!bpf_loader::check_id(program_id)); + // Log the provided account keys and instruction input data. In the case of // the no-op program, no account keys or input data are expected but real // programs will have specific requirements so they can do their work. diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 4a5fcfc529..e56ee1d183 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -9,6 +9,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use solana_rbpf::{memory_region::MemoryRegion, EbpfVm}; use solana_sdk::{ account::KeyedAccount, + bpf_loader, entrypoint::SUCCESS, instruction::InstructionError, loader_instruction::LoaderInstruction, @@ -147,6 +148,8 @@ pub fn process_instruction( ) -> Result<(), InstructionError> { solana_logger::setup_with_default("solana=info"); + debug_assert!(bpf_loader::check_id(program_id)); + if keyed_accounts.is_empty() { warn!("No account keys"); return Err(InstructionError::NotEnoughAccountKeys); @@ -164,8 +167,11 @@ pub fn process_instruction( } }; let parameter_accounts = keyed_accounts_iter.as_slice(); - let parameter_bytes = - serialize_parameters(program_id, parameter_accounts, &instruction_data)?; + let parameter_bytes = serialize_parameters( + program.unsigned_key(), + parameter_accounts, + &instruction_data, + )?; info!("Call BPF program"); match vm.execute_program(parameter_bytes.as_slice(), &[], &[heap_region]) { @@ -265,13 +271,13 @@ mod tests { // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &vec![], &instruction_data) + process_instruction(&bpf_loader::id(), &vec![], &instruction_data) ); // Case: Not signed assert_eq!( Err(InstructionError::MissingRequiredSignature), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); // Case: Write bytes to an offset @@ -279,7 +285,7 @@ mod tests { keyed_accounts[0].account.borrow_mut().data = vec![0; 6]; assert_eq!( Ok(()), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); assert_eq!( vec![0, 0, 0, 1, 2, 3], @@ -291,7 +297,7 @@ mod tests { keyed_accounts[0].account.borrow_mut().data = vec![0; 5]; assert_eq!( Err(InstructionError::AccountDataTooSmall), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); } @@ -312,7 +318,7 @@ mod tests { // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &vec![], &instruction_data) + process_instruction(&bpf_loader::id(), &vec![], &instruction_data) ); let rent_account = RefCell::new(rent::create_account(1, &rent)); @@ -321,7 +327,7 @@ mod tests { // Case: Not signed assert_eq!( Err(InstructionError::MissingRequiredSignature), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); // Case: Finalize @@ -331,7 +337,7 @@ mod tests { ]; assert_eq!( Ok(()), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); assert!(keyed_accounts[0].account.borrow().executable); @@ -345,7 +351,7 @@ mod tests { ]; assert_eq!( Err(InstructionError::InvalidAccountData), - process_instruction(&program_id, &keyed_accounts, &instruction_data) + process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data) ); } @@ -369,20 +375,20 @@ mod tests { // Case: Empty keyed accounts assert_eq!( Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&program_id, &vec![], &vec![]) + process_instruction(&bpf_loader::id(), &vec![], &vec![]) ); // Case: Only a program account assert_eq!( Ok(()), - process_instruction(&program_id, &keyed_accounts, &vec![]) + process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]) ); // Case: Account not executable keyed_accounts[0].account.borrow_mut().executable = false; assert_eq!( Err(InstructionError::InvalidInstructionData), - process_instruction(&program_id, &keyed_accounts, &vec![]) + process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]) ); keyed_accounts[0].account.borrow_mut().executable = true; @@ -391,7 +397,7 @@ mod tests { keyed_accounts.push(KeyedAccount::new(&program_key, false, ¶meter_account)); assert_eq!( Ok(()), - process_instruction(&program_id, &keyed_accounts, &vec![]) + process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]) ); // Case: With duplicate accounts @@ -402,7 +408,7 @@ mod tests { keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); assert_eq!( Ok(()), - process_instruction(&program_id, &keyed_accounts, &vec![]) + process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]) ); } } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 7e06bf30dd..31b5b2f89b 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4884,10 +4884,13 @@ mod tests { let mut bank = Bank::new(&genesis_config); fn mock_vote_processor( - _pubkey: &Pubkey, - _ka: &[KeyedAccount], - _data: &[u8], + program_id: &Pubkey, + _keyed_accounts: &[KeyedAccount], + _instruction_data: &[u8], ) -> std::result::Result<(), InstructionError> { + if !solana_vote_program::check_id(program_id) { + return Err(InstructionError::IncorrectProgramId); + } Err(InstructionError::CustomError(42)) } diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 93fe6726d0..55dd5d0be9 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -6,6 +6,7 @@ use solana_sdk::{ entrypoint_native, instruction::{CompiledInstruction, InstructionError}, message::Message, + native_loader::id as native_loader_id, pubkey::Pubkey, system_program, transaction::TransactionError, @@ -172,7 +173,6 @@ impl MessageProcessor { executable_accounts: &[(Pubkey, RefCell)], program_accounts: &[Rc>], ) -> Result<(), InstructionError> { - let program_id = instruction.program_id(&message.account_keys); let mut keyed_accounts = create_keyed_readonly_accounts(executable_accounts); let mut keyed_accounts2: Vec<_> = instruction .accounts @@ -202,12 +202,16 @@ impl MessageProcessor { let root_program_id = keyed_accounts[0].unsigned_key(); for (id, process_instruction) in &self.instruction_processors { if id == root_program_id { - return process_instruction(&program_id, &keyed_accounts[1..], &instruction.data); + return process_instruction( + &root_program_id, + &keyed_accounts[1..], + &instruction.data, + ); } } native_loader::invoke_entrypoint( - &program_id, + &native_loader_id(), &keyed_accounts, &instruction.data, &self.symbol_cache, diff --git a/runtime/src/native_loader.rs b/runtime/src/native_loader.rs index a9d6711229..52c83f9b03 100644 --- a/runtime/src/native_loader.rs +++ b/runtime/src/native_loader.rs @@ -83,7 +83,7 @@ fn library_open(path: &PathBuf) -> std::io::Result { } pub fn invoke_entrypoint( - program_id: &Pubkey, + _program_id: &Pubkey, keyed_accounts: &[KeyedAccount], instruction_data: &[u8], symbol_cache: &SymbolCache, @@ -94,7 +94,7 @@ pub fn invoke_entrypoint( let name_vec = &program.try_account_ref()?.data; if let Some(entrypoint) = symbol_cache.read().unwrap().get(name_vec) { unsafe { - return entrypoint(program_id, params, instruction_data); + return entrypoint(names[0].unsigned_key(), params, instruction_data); } } let name = match str::from_utf8(name_vec) { @@ -120,7 +120,7 @@ pub fn invoke_entrypoint( return Err(NativeLoaderError::EntrypointNotFound.into()); } }; - let ret = entrypoint(program_id, params, instruction_data); + let ret = entrypoint(names[0].unsigned_key(), params, instruction_data); symbol_cache .write() .unwrap() diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index d559886a3c..4ad5bb3342 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -3,6 +3,10 @@ use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey}; // Prototype of a native program entry point +/// +/// program_id: Program ID of the currently executing program +/// keyed_accounts: Accounts passed as part of the instruction +/// instruction_data: Instruction data pub type Entrypoint = unsafe extern "C" fn( program_id: &Pubkey, keyed_accounts: &[KeyedAccount],