Refactor verify_and_update write privileges check (#18468)

This commit is contained in:
Justin Starry 2021-07-07 09:14:00 -05:00 committed by GitHub
parent a0551b4054
commit 72da25e9d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 27 deletions

View File

@ -390,10 +390,9 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
} }
fn verify_and_update( fn verify_and_update(
&mut self, &mut self,
message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_write_privileges: Option<&[bool]>, write_privileges: &[bool],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let stack_frame = self let stack_frame = self
.invoke_stack .invoke_stack
@ -401,13 +400,12 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
.ok_or(InstructionError::CallDepth)?; .ok_or(InstructionError::CallDepth)?;
let logger = self.get_logger(); let logger = self.get_logger();
MessageProcessor::verify_and_update( MessageProcessor::verify_and_update(
message,
instruction, instruction,
&mut self.pre_accounts, &mut self.pre_accounts,
accounts, accounts,
&stack_frame.key, &stack_frame.key,
&self.rent, &self.rent,
caller_write_privileges, write_privileges,
&mut self.timings, &mut self.timings,
logger, logger,
) )
@ -913,12 +911,7 @@ impl MessageProcessor {
let program_id = instruction.program_id(&message.account_keys); let program_id = instruction.program_id(&message.account_keys);
// Verify the calling program hasn't misbehaved // Verify the calling program hasn't misbehaved
invoke_context.verify_and_update( invoke_context.verify_and_update(instruction, accounts, caller_write_privileges)?;
message,
instruction,
accounts,
Some(caller_write_privileges),
)?;
// Construct keyed accounts // Construct keyed accounts
let keyed_accounts = let keyed_accounts =
@ -939,7 +932,10 @@ impl MessageProcessor {
); );
if result.is_ok() { if result.is_ok() {
// Verify the called program has not misbehaved // Verify the called program has not misbehaved
result = invoke_context.verify_and_update(message, instruction, accounts, None); let write_privileges: Vec<bool> = (0..message.account_keys.len())
.map(|i| message.is_writable(i))
.collect();
result = invoke_context.verify_and_update(instruction, accounts, &write_privileges);
} }
// Restore previous state // Restore previous state
@ -1047,26 +1043,21 @@ impl MessageProcessor {
/// Verify the results of a cross-program instruction /// Verify the results of a cross-program instruction
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn verify_and_update( fn verify_and_update(
message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
pre_accounts: &mut [PreAccount], pre_accounts: &mut [PreAccount],
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
program_id: &Pubkey, program_id: &Pubkey,
rent: &Rent, rent: &Rent,
caller_write_privileges: Option<&[bool]>, write_privileges: &[bool],
timings: &mut ExecuteDetailsTimings, timings: &mut ExecuteDetailsTimings,
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// Verify the per-account instruction results // Verify the per-account instruction results
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128); let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
let mut work = |_unique_index: usize, account_index: usize| { let mut work = |_unique_index: usize, account_index: usize| {
if account_index < message.account_keys.len() && account_index < accounts.len() { if account_index < write_privileges.len() && account_index < accounts.len() {
let (key, account) = &accounts[account_index]; let (key, account) = &accounts[account_index];
let is_writable = if let Some(caller_write_privileges) = caller_write_privileges { let is_writable = write_privileges[account_index];
caller_write_privileges[account_index]
} else {
message.is_writable(account_index)
};
// Find the matching PreAccount // Find the matching PreAccount
for pre_account in pre_accounts.iter_mut() { for pre_account in pre_accounts.iter_mut() {
if key == pre_account.key() { if key == pre_account.key() {
@ -1332,8 +1323,11 @@ mod tests {
&solana_sdk::pubkey::Pubkey::default(), &solana_sdk::pubkey::Pubkey::default(),
))), ))),
)); ));
let write_privileges: Vec<bool> = (0..message.account_keys.len())
.map(|i| message.is_writable(i))
.collect();
invoke_context invoke_context
.verify_and_update(&message, &message.instructions[0], &these_accounts, None) .verify_and_update(&message.instructions[0], &these_accounts, &write_privileges)
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
invoke_context.pre_accounts[owned_index] invoke_context.pre_accounts[owned_index]
@ -1349,10 +1343,9 @@ mod tests {
(MAX_DEPTH + not_owned_index) as u8; (MAX_DEPTH + not_owned_index) as u8;
assert_eq!( assert_eq!(
invoke_context.verify_and_update( invoke_context.verify_and_update(
&message,
&message.instructions[0], &message.instructions[0],
&accounts[not_owned_index..owned_index + 1], &accounts[not_owned_index..owned_index + 1],
None &write_privileges,
), ),
Err(InstructionError::ExternalAccountDataModified) Err(InstructionError::ExternalAccountDataModified)
); );

View File

@ -2,7 +2,6 @@ use solana_sdk::{
account::AccountSharedData, account::AccountSharedData,
instruction::{CompiledInstruction, Instruction, InstructionError}, instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::{create_keyed_accounts_unified, KeyedAccount}, keyed_account::{create_keyed_accounts_unified, KeyedAccount},
message::Message,
pubkey::Pubkey, pubkey::Pubkey,
sysvar::Sysvar, sysvar::Sysvar,
}; };
@ -62,10 +61,9 @@ pub trait InvokeContext {
/// Verify and update PreAccount state based on program execution /// Verify and update PreAccount state based on program execution
fn verify_and_update( fn verify_and_update(
&mut self, &mut self,
message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_pivileges: Option<&[bool]>, write_privileges: &[bool],
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
/// Get the program ID of the currently executing program /// Get the program ID of the currently executing program
fn get_caller(&self) -> Result<&Pubkey, InstructionError>; fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
@ -393,10 +391,9 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
} }
fn verify_and_update( fn verify_and_update(
&mut self, &mut self,
_message: &Message,
_instruction: &CompiledInstruction, _instruction: &CompiledInstruction,
_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], _accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
_caller_pivileges: Option<&[bool]>, _write_pivileges: &[bool],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
Ok(()) Ok(())
} }