Enforce an executable's rent exemption in the runtime (#9134)

This commit is contained in:
Jack May
2020-03-31 10:07:38 -07:00
committed by GitHub
parent 974848310c
commit 130c0b484d
6 changed files with 110 additions and 92 deletions

View File

@ -21,7 +21,6 @@ use solana_sdk::{
program_utils::DecodeError,
program_utils::{is_executable, limited_deserialize, next_keyed_account},
pubkey::Pubkey,
sysvar::rent,
};
use std::{io::prelude::*, mem};
use thiserror::Error;
@ -229,7 +228,6 @@ pub fn process_instruction(
LoaderInstruction::Finalize => {
let mut keyed_accounts_iter = keyed_accounts.iter();
let program = next_keyed_account(&mut keyed_accounts_iter)?;
let rent = next_keyed_account(&mut keyed_accounts_iter)?;
if program.signer_key().is_none() {
warn!("key[0] did not sign the transaction");
@ -241,8 +239,6 @@ pub fn process_instruction(
return Err(InstructionError::InvalidAccountData);
}
rent::verify_rent_exemption(&program, &rent)?;
program.try_account_ref_mut()?.executable = true;
info!("Finalize: account {:?}", program.signer_key().unwrap());
}
@ -254,8 +250,8 @@ pub fn process_instruction(
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::account::Account;
use std::{cell::RefCell, fs::File, io::Read};
use solana_sdk::{account::Account, rent::Rent};
use std::{fs::File, io::Read};
#[test]
#[should_panic(expected = "ExceededMaxInstructions(10)")]
@ -324,14 +320,13 @@ mod tests {
fn test_bpf_loader_finalize() {
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();
let rent_key = rent::id();
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
let mut elf = Vec::new();
let rent = rent::Rent::default();
let rent = Rent::default();
file.read_to_end(&mut elf).unwrap();
let program_account = Account::new_ref(rent.minimum_balance(elf.len()), 0, &program_id);
program_account.borrow_mut().data = elf;
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];
let keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];
let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap();
// Case: Empty keyed accounts
@ -340,9 +335,6 @@ mod tests {
process_instruction(&bpf_loader::id(), &vec![], &instruction_data)
);
let rent_account = RefCell::new(rent::create_account(1, &rent));
keyed_accounts.push(KeyedAccount::new(&rent_key, false, &rent_account));
// Case: Not signed
assert_eq!(
Err(InstructionError::MissingRequiredSignature),
@ -350,10 +342,7 @@ mod tests {
);
// Case: Finalize
let keyed_accounts = vec![
KeyedAccount::new(&program_key, true, &program_account),
KeyedAccount::new(&rent_key, false, &rent_account),
];
let keyed_accounts = vec![KeyedAccount::new(&program_key, true, &program_account)];
assert_eq!(
Ok(()),
process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data)
@ -364,10 +353,7 @@ mod tests {
// Case: Finalize
program_account.borrow_mut().data[0] = 0; // bad elf
let keyed_accounts = vec![
KeyedAccount::new(&program_key, true, &program_account),
KeyedAccount::new(&rent_key, false, &rent_account),
];
let keyed_accounts = vec![KeyedAccount::new(&program_key, true, &program_account)];
assert_eq!(
Err(InstructionError::InvalidAccountData),
process_instruction(&bpf_loader::id(), &keyed_accounts, &instruction_data)

View File

@ -13,7 +13,6 @@ use solana_sdk::{
program_utils::DecodeError,
program_utils::{is_executable, limited_deserialize, next_keyed_account},
pubkey::Pubkey,
sysvar::rent,
};
use thiserror::Error;
use types::{
@ -73,7 +72,6 @@ pub enum MoveLoaderInstruction {
/// bit of the Account
///
/// * key[0] - the account to prepare for execution
/// * key[1] - rent sysvar account
///
/// The transaction must be signed by key[0]
Finalize,
@ -301,15 +299,12 @@ impl MoveProcessor {
pub fn do_finalize(keyed_accounts: &[KeyedAccount]) -> Result<(), InstructionError> {
let mut keyed_accounts_iter = keyed_accounts.iter();
let finalized = next_keyed_account(&mut keyed_accounts_iter)?;
let rent = next_keyed_account(&mut keyed_accounts_iter)?;
if finalized.signer_key().is_none() {
debug!("Error: account to finalize did not sign the transaction");
return Err(InstructionError::MissingRequiredSignature);
}
rent::verify_rent_exemption(&finalized, &rent)?;
match finalized.state()? {
LibraAccountState::CompiledScript(string) => {
let script: Script = serde_json::from_str(&string).map_err(map_json_error)?;
@ -479,8 +474,6 @@ impl MoveProcessor {
mod tests {
use super::*;
use solana_sdk::account::Account;
use solana_sdk::rent::Rent;
use solana_sdk::sysvar::rent;
use std::cell::RefCell;
const BIG_ENOUGH: usize = 10_000;
@ -518,11 +511,8 @@ mod tests {
let code = "main() { return; }";
let sender_address = AccountAddress::default();
let script = LibraAccount::create_script(&sender_address, code, vec![]);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();
let _ = MoveProcessor::deserialize_verified_script(&script.account.borrow().data).unwrap();
@ -561,11 +551,8 @@ mod tests {
let script = LibraAccount::create_script(&sender_address, code, vec![]);
let genesis = LibraAccount::create_genesis(1_000_000_000);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();
@ -591,11 +578,8 @@ mod tests {
}
";
let module = LibraAccount::create_module(code, vec![]);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&module.key, true, &module.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
keyed_accounts[0]
.account
@ -620,11 +604,8 @@ mod tests {
let script = LibraAccount::create_script(&sender_address, code, vec![]);
let genesis = LibraAccount::create_genesis(1_000_000_000);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();
@ -695,11 +676,8 @@ mod tests {
let script = LibraAccount::create_script(&genesis.address, code, vec![]);
let payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();
@ -753,11 +731,8 @@ mod tests {
);
let module = LibraAccount::create_module(&code, vec![]);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&module.key, true, &module.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
keyed_accounts[0]
.account
@ -799,11 +774,8 @@ mod tests {
);
let payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();
@ -849,11 +821,8 @@ mod tests {
let script = LibraAccount::create_script(&genesis.address.clone(), code, vec![]);
let payee = LibraAccount::create_unallocated(BIG_ENOUGH);
let rent_id = rent::id();
let rent_account = RefCell::new(rent::create_account(1, &Rent::free()));
let keyed_accounts = vec![
KeyedAccount::new(&script.key, true, &script.account),
KeyedAccount::new(&rent_id, false, &rent_account),
];
MoveProcessor::do_finalize(&keyed_accounts).unwrap();