Check CPI program is executable (#12644)
This commit is contained in:
@ -7,6 +7,7 @@
|
|||||||
static const uint8_t TEST_SUCCESS = 1;
|
static const uint8_t TEST_SUCCESS = 1;
|
||||||
static const uint8_t TEST_PRIVILEGE_ESCALATION_SIGNER = 2;
|
static const uint8_t TEST_PRIVILEGE_ESCALATION_SIGNER = 2;
|
||||||
static const uint8_t TEST_PRIVILEGE_ESCALATION_WRITABLE = 3;
|
static const uint8_t TEST_PRIVILEGE_ESCALATION_WRITABLE = 3;
|
||||||
|
static const uint8_t TEST_PPROGRAM_NOT_EXECUTABLE = 4;
|
||||||
|
|
||||||
static const int MINT_INDEX = 0;
|
static const int MINT_INDEX = 0;
|
||||||
static const int ARGUMENT_INDEX = 1;
|
static const int ARGUMENT_INDEX = 1;
|
||||||
@ -272,6 +273,16 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
|
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TEST_PPROGRAM_NOT_EXECUTABLE: {
|
||||||
|
sol_log("Test program not executable");
|
||||||
|
SolAccountMeta arguments[] = {
|
||||||
|
{accounts[DERIVED_KEY3_INDEX].key, false, false}};
|
||||||
|
uint8_t data[] = {TEST_VERIFY_PRIVILEGE_ESCALATION};
|
||||||
|
const SolInstruction instruction = {accounts[ARGUMENT_INDEX].key, arguments,
|
||||||
|
SOL_ARRAY_SIZE(arguments), data,
|
||||||
|
SOL_ARRAY_SIZE(data)};
|
||||||
|
return sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
sol_panic();
|
sol_panic();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use solana_sdk::{
|
|||||||
const TEST_SUCCESS: u8 = 1;
|
const TEST_SUCCESS: u8 = 1;
|
||||||
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
||||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||||
|
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
|
||||||
|
|
||||||
// const MINT_INDEX: usize = 0;
|
// const MINT_INDEX: usize = 0;
|
||||||
const ARGUMENT_INDEX: usize = 1;
|
const ARGUMENT_INDEX: usize = 1;
|
||||||
@ -241,10 +242,7 @@ fn process_instruction(
|
|||||||
|
|
||||||
// Signer privilege escalation will always fail the whole transaction
|
// Signer privilege escalation will always fail the whole transaction
|
||||||
invoked_instruction.accounts[0].is_signer = true;
|
invoked_instruction.accounts[0].is_signer = true;
|
||||||
assert_eq!(
|
invoke(&invoked_instruction, accounts)?;
|
||||||
invoke(&invoked_instruction, accounts),
|
|
||||||
Err(ProgramError::Custom(0x0b9f_0002))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
TEST_PRIVILEGE_ESCALATION_WRITABLE => {
|
TEST_PRIVILEGE_ESCALATION_WRITABLE => {
|
||||||
info!("Test privilege escalation writable");
|
info!("Test privilege escalation writable");
|
||||||
@ -257,10 +255,17 @@ fn process_instruction(
|
|||||||
|
|
||||||
// Writable privilege escalation will always fail the whole transaction
|
// Writable privilege escalation will always fail the whole transaction
|
||||||
invoked_instruction.accounts[0].is_writable = true;
|
invoked_instruction.accounts[0].is_writable = true;
|
||||||
assert_eq!(
|
|
||||||
invoke(&invoked_instruction, accounts),
|
invoke(&invoked_instruction, accounts)?;
|
||||||
Err(ProgramError::Custom(0x0b9f_0002))
|
}
|
||||||
|
TEST_PPROGRAM_NOT_EXECUTABLE => {
|
||||||
|
info!("Test program not executable");
|
||||||
|
let instruction = create_instruction(
|
||||||
|
*accounts[ARGUMENT_INDEX].key,
|
||||||
|
&[(accounts[ARGUMENT_INDEX].key, true, true)],
|
||||||
|
vec![TEST_RETURN_ERROR],
|
||||||
);
|
);
|
||||||
|
invoke(&instruction, accounts)?;
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
|
@ -435,6 +435,7 @@ fn test_program_bpf_invoke() {
|
|||||||
const TEST_SUCCESS: u8 = 1;
|
const TEST_SUCCESS: u8 = 1;
|
||||||
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2;
|
||||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||||
|
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
|
||||||
|
|
||||||
let mut programs = Vec::new();
|
let mut programs = Vec::new();
|
||||||
#[cfg(feature = "bpf_c")]
|
#[cfg(feature = "bpf_c")]
|
||||||
@ -595,6 +596,35 @@ fn test_program_bpf_invoke() {
|
|||||||
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
TransactionError::InstructionError(0, InstructionError::Custom(194969602))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let instruction = Instruction::new(
|
||||||
|
invoke_program_id,
|
||||||
|
&[TEST_PPROGRAM_NOT_EXECUTABLE, nonce1, nonce2, nonce3],
|
||||||
|
account_metas.clone(),
|
||||||
|
);
|
||||||
|
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||||
|
let tx = Transaction::new(
|
||||||
|
&[
|
||||||
|
&mint_keypair,
|
||||||
|
&argument_keypair,
|
||||||
|
&invoked_argument_keypair,
|
||||||
|
&from_keypair,
|
||||||
|
],
|
||||||
|
message.clone(),
|
||||||
|
bank.last_blockhash(),
|
||||||
|
);
|
||||||
|
let (result, inner_instructions) = process_transaction_and_record_inner(&bank, tx);
|
||||||
|
let invoked_programs: Vec<Pubkey> = inner_instructions[0]
|
||||||
|
.iter()
|
||||||
|
.map(|ix| message.account_keys[ix.program_id_index as usize].clone())
|
||||||
|
.collect();
|
||||||
|
assert_eq!(invoked_programs, vec![argument_keypair.pubkey().clone()]);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err(),
|
||||||
|
TransactionError::InstructionError(0, InstructionError::AccountNotExecutable)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check final state
|
||||||
|
|
||||||
assert_eq!(43, bank.get_balance(&derived_key1));
|
assert_eq!(43, bank.get_balance(&derived_key1));
|
||||||
let account = bank.get_account(&derived_key1).unwrap();
|
let account = bank.get_account(&derived_key1).unwrap();
|
||||||
assert_eq!(invoke_program_id, account.owner);
|
assert_eq!(invoke_program_id, account.owner);
|
||||||
@ -632,12 +662,12 @@ fn assert_instruction_count() {
|
|||||||
("solana_bpf_rust_128bit", 543),
|
("solana_bpf_rust_128bit", 543),
|
||||||
("solana_bpf_rust_alloc", 19082),
|
("solana_bpf_rust_alloc", 19082),
|
||||||
("solana_bpf_rust_dep_crate", 2),
|
("solana_bpf_rust_dep_crate", 2),
|
||||||
("solana_bpf_rust_external_spend", 477),
|
("solana_bpf_rust_external_spend", 485),
|
||||||
("solana_bpf_rust_iter", 723),
|
("solana_bpf_rust_iter", 723),
|
||||||
("solana_bpf_rust_many_args", 231),
|
("solana_bpf_rust_many_args", 231),
|
||||||
("solana_bpf_rust_noop", 451),
|
("solana_bpf_rust_noop", 459),
|
||||||
("solana_bpf_rust_param_passing", 54),
|
("solana_bpf_rust_param_passing", 54),
|
||||||
("solana_bpf_rust_sanity", 2215),
|
("solana_bpf_rust_sanity", 2223),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,6 +1088,9 @@ fn call<'a>(
|
|||||||
// Process instruction
|
// Process instruction
|
||||||
|
|
||||||
let program_account = (*accounts[callee_program_id_index]).clone();
|
let program_account = (*accounts[callee_program_id_index]).clone();
|
||||||
|
if !program_account.borrow().executable {
|
||||||
|
return Err(SyscallError::InstructionError(InstructionError::AccountNotExecutable).into());
|
||||||
|
}
|
||||||
let executable_accounts = vec![(callee_program_id, program_account)];
|
let executable_accounts = vec![(callee_program_id, program_account)];
|
||||||
let mut message_processor = MessageProcessor::default();
|
let mut message_processor = MessageProcessor::default();
|
||||||
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
|
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
|
||||||
|
@ -457,7 +457,6 @@ impl MessageProcessor {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
keyed_accounts.append(&mut keyed_accounts2);
|
keyed_accounts.append(&mut keyed_accounts2);
|
||||||
assert!(keyed_accounts[0].executable()?, "account not executable");
|
|
||||||
Ok(keyed_accounts)
|
Ok(keyed_accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user