Respect RefCell when calling invoke (#12858) (#12891)

* Respect RefCell when calling invoke

* nudge

(cherry picked from commit 969f7b015b)

Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
mergify[bot]
2020-10-15 02:15:36 +00:00
committed by GitHub
parent ceeeb3c9dd
commit bc96332899
3 changed files with 157 additions and 13 deletions

View File

@ -144,6 +144,92 @@ fn process_instruction(
);
}
info!("Test refcell usage");
{
let writable = INVOKED_ARGUMENT_INDEX;
let readable = INVOKED_PROGRAM_INDEX;
let instruction = create_instruction(
*accounts[INVOKED_PROGRAM_INDEX].key,
&[
(accounts[writable].key, true, true),
(accounts[readable].key, false, false),
],
vec![TEST_RETURN_ERROR, 1, 2, 3, 4, 5],
);
// success with this account configuration as a check
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::Custom(42))
);
{
// writable but lamports borrow_mut'd
let _ref_mut = accounts[writable].try_borrow_mut_lamports()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// writable but data borrow_mut'd
let _ref_mut = accounts[writable].try_borrow_mut_data()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// writable but lamports borrow'd
let _ref_mut = accounts[writable].try_borrow_lamports()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// writable but data borrow'd
let _ref_mut = accounts[writable].try_borrow_data()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// readable but lamports borrow_mut'd
let _ref_mut = accounts[readable].try_borrow_mut_lamports()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// readable but data borrow_mut'd
let _ref_mut = accounts[readable].try_borrow_mut_data()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::AccountBorrowFailed)
);
}
{
// readable but lamports borrow'd
let _ref_mut = accounts[readable].try_borrow_lamports()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::Custom(42))
);
}
{
// readable but data borrow'd
let _ref_mut = accounts[readable].try_borrow_data()?;
assert_eq!(
invoke(&instruction, accounts),
Err(ProgramError::Custom(42))
);
}
}
info!("Test create_program_address");
{
assert_eq!(

View File

@ -444,16 +444,25 @@ fn test_program_bpf_invoke() {
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
#[allow(dead_code)]
#[derive(Debug)]
enum Languages {
C,
Rust,
}
let mut programs = Vec::new();
#[cfg(feature = "bpf_c")]
{
programs.extend_from_slice(&[("invoke", "invoked")]);
programs.push((Languages::C, "invoke", "invoked"));
}
#[cfg(feature = "bpf_rust")]
{
programs.extend_from_slice(&[("solana_bpf_rust_invoke", "solana_bpf_rust_invoked")]);
programs.push((
Languages::Rust,
"solana_bpf_rust_invoke",
"solana_bpf_rust_invoked",
));
}
for program in programs.iter() {
println!("Test program: {:?}", program);
@ -469,9 +478,9 @@ fn test_program_bpf_invoke() {
let bank_client = BankClient::new_shared(&bank);
let invoke_program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.0);
let invoked_program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.1);
let invoked_program_id =
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.2);
let argument_keypair = Keypair::new();
let account = Account::new(42, 100, &invoke_program_id);
@ -531,9 +540,9 @@ fn test_program_bpf_invoke() {
.iter()
.map(|ix| message.account_keys[ix.program_id_index as usize].clone())
.collect();
assert_eq!(
invoked_programs,
vec![
let expected_invoked_programs = match program.0 {
Languages::C => vec![
solana_sdk::system_program::id(),
solana_sdk::system_program::id(),
invoked_program_id.clone(),
@ -546,14 +555,37 @@ fn test_program_bpf_invoke() {
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
]
);
],
Languages::Rust => vec![
solana_sdk::system_program::id(),
solana_sdk::system_program::id(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
],
};
assert_eq!(invoked_programs, expected_invoked_programs);
// failure cases
let instruction = Instruction::new(
invoke_program_id,
&[TEST_PRIVILEGE_ESCALATION_SIGNER, bump_seed1, bump_seed2, bump_seed3],
&[
TEST_PRIVILEGE_ESCALATION_SIGNER,
bump_seed1,
bump_seed2,
bump_seed3,
],
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));
@ -581,7 +613,12 @@ fn test_program_bpf_invoke() {
let instruction = Instruction::new(
invoke_program_id,
&[TEST_PRIVILEGE_ESCALATION_WRITABLE, bump_seed1, bump_seed2, bump_seed3],
&[
TEST_PRIVILEGE_ESCALATION_WRITABLE,
bump_seed1,
bump_seed2,
bump_seed3,
],
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));
@ -608,7 +645,12 @@ fn test_program_bpf_invoke() {
let instruction = Instruction::new(
invoke_program_id,
&[TEST_PPROGRAM_NOT_EXECUTABLE, bump_seed1, bump_seed2, bump_seed3],
&[
TEST_PPROGRAM_NOT_EXECUTABLE,
bump_seed1,
bump_seed2,
bump_seed3,
],
account_metas.clone(),
);
let message = Message::new(&[instruction], Some(&mint_pubkey));

View File

@ -16,6 +16,22 @@ pub fn invoke_signed(
account_infos: &[AccountInfo],
signers_seeds: &[&[&[u8]]],
) -> ProgramResult {
// Check that the account RefCells are consistent with the request
for account_meta in instruction.accounts.iter() {
for account_info in account_infos.iter() {
if account_meta.pubkey == *account_info.key {
if account_meta.is_writable {
let _ = account_info.try_borrow_mut_lamports()?;
let _ = account_info.try_borrow_mut_data()?;
} else {
let _ = account_info.try_borrow_lamports()?;
let _ = account_info.try_borrow_data()?;
}
break;
}
}
}
let result = unsafe {
sol_invoke_signed_rust(
instruction as *const _ as *const u8,