Disable cross-program invocations for OperatingMode::Stable (bp #11272) (#11280)

* Disable cross-program invocations for OperatingMode::Stable (#11272)

(cherry picked from commit 2dbed80e48)

# Conflicts:
#	programs/bpf/benches/bpf_loader.rs
#	programs/bpf_loader/src/lib.rs
#	runtime/src/message_processor.rs
#	sdk/src/entrypoint_native.rs

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
mergify[bot]
2020-07-30 05:50:47 +00:00
committed by GitHub
parent da4642d634
commit 5dc4410d58
8 changed files with 58 additions and 5 deletions

View File

@ -107,6 +107,7 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch
bank.add_native_program(name, program_id); bank.add_native_program(name, program_id);
} }
} }
bank.set_cross_program_support(OperatingMode::Stable != operating_mode);
}) })
} }

View File

@ -159,4 +159,7 @@ impl InvokeContext for MockInvokeContext {
false false
} }
fn log(&mut self, _message: &str) {} fn log(&mut self, _message: &str) {}
fn is_cross_program_supported(&self) -> bool {
true
}
} }

View File

@ -356,7 +356,8 @@ mod bpf {
let derived_key2 = let derived_key2 =
Pubkey::create_program_address(&[b"Lil'", b"Bits"], &invoked_program_id).unwrap(); Pubkey::create_program_address(&[b"Lil'", b"Bits"], &invoked_program_id).unwrap();
let derived_key3 = let derived_key3 =
Pubkey::create_program_address(&[derived_key2.as_ref()], &invoked_program_id).unwrap(); Pubkey::create_program_address(&[derived_key2.as_ref()], &invoked_program_id)
.unwrap();
let mint_pubkey = mint_keypair.pubkey(); let mint_pubkey = mint_keypair.pubkey();
let account_metas = vec![ let account_metas = vec![

View File

@ -295,6 +295,9 @@ mod tests {
info!("[MockInvokeContext::log] {}", message); info!("[MockInvokeContext::log] {}", message);
self.log.push(message.to_string()); self.log.push(message.to_string());
} }
fn is_cross_program_supported(&self) -> bool {
true
}
} }
#[rustversion::since(1.46.0)] #[rustversion::since(1.46.0)]

View File

@ -825,6 +825,7 @@ fn call<'a>(
message_processor.add_program(*program_id, *process_instruction); message_processor.add_program(*program_id, *process_instruction);
} }
message_processor.add_loader(bpf_loader::id(), crate::process_instruction); message_processor.add_loader(bpf_loader::id(), crate::process_instruction);
message_processor.set_cross_program_support(invoke_context.is_cross_program_supported());
#[allow(clippy::deref_addrof)] #[allow(clippy::deref_addrof)]
match message_processor.process_cross_program_instruction( match message_processor.process_cross_program_instruction(

View File

@ -373,6 +373,9 @@ impl Bank {
bank.update_rent(); bank.update_rent();
bank.update_epoch_schedule(); bank.update_epoch_schedule();
bank.update_recent_blockhashes(); bank.update_recent_blockhashes();
if bank.operating_mode == Some(OperatingMode::Stable) {
bank.message_processor.set_cross_program_support(false);
}
bank bank
} }
@ -977,6 +980,11 @@ impl Bank {
debug!("Added native program {} under {:?}", name, program_id); debug!("Added native program {} under {:?}", name, program_id);
} }
pub fn set_cross_program_support(&mut self, is_supported: bool) {
self.message_processor
.set_cross_program_support(is_supported);
}
/// Return the last block hash registered. /// Return the last block hash registered.
pub fn last_blockhash(&self) -> Hash { pub fn last_blockhash(&self) -> Hash {
self.blockhash_queue.read().unwrap().last_hash() self.blockhash_queue.read().unwrap().last_hash()

View File

@ -161,6 +161,7 @@ pub struct ThisInvokeContext<'a> {
pub pre_accounts: Vec<PreAccount>, pub pre_accounts: Vec<PreAccount>,
pub programs: Vec<(Pubkey, ProcessInstruction)>, pub programs: Vec<(Pubkey, ProcessInstruction)>,
pub log_collector: Option<&'a LogCollector>, pub log_collector: Option<&'a LogCollector>,
is_cross_program_supported: bool,
} }
impl<'a> ThisInvokeContext<'a> { impl<'a> ThisInvokeContext<'a> {
@ -171,6 +172,7 @@ impl<'a> ThisInvokeContext<'a> {
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
log_collector: Option<&'a LogCollector>, log_collector: Option<&'a LogCollector>,
is_cross_program_supported: bool,
) -> Self { ) -> Self {
let mut program_ids = Vec::with_capacity(Self::MAX_INVOCATION_DEPTH); let mut program_ids = Vec::with_capacity(Self::MAX_INVOCATION_DEPTH);
program_ids.push(*program_id); program_ids.push(*program_id);
@ -180,6 +182,7 @@ impl<'a> ThisInvokeContext<'a> {
pre_accounts, pre_accounts,
programs, programs,
log_collector, log_collector,
is_cross_program_supported,
} }
} }
} }
@ -226,7 +229,6 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] { fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
&self.programs &self.programs
} }
fn log_enabled(&self) -> bool { fn log_enabled(&self) -> bool {
log_enabled!(log::Level::Info) || self.log_collector.is_some() log_enabled!(log::Level::Info) || self.log_collector.is_some()
} }
@ -237,12 +239,15 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
log_collector.log(message); log_collector.log(message);
} }
} }
fn is_cross_program_supported(&self) -> bool {
self.is_cross_program_supported
}
} }
pub type ProcessInstructionWithContext = pub type ProcessInstructionWithContext =
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
#[derive(Default, Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct MessageProcessor { pub struct MessageProcessor {
#[serde(skip)] #[serde(skip)]
programs: Vec<(Pubkey, ProcessInstruction)>, programs: Vec<(Pubkey, ProcessInstruction)>,
@ -250,6 +255,18 @@ pub struct MessageProcessor {
loaders: Vec<(Pubkey, ProcessInstructionWithContext)>, loaders: Vec<(Pubkey, ProcessInstructionWithContext)>,
#[serde(skip)] #[serde(skip)]
native_loader: NativeLoader, native_loader: NativeLoader,
#[serde(skip)]
is_cross_program_supported: bool,
}
impl Default for MessageProcessor {
fn default() -> Self {
Self {
programs: vec![],
loaders: vec![],
native_loader: NativeLoader::default(),
is_cross_program_supported: true,
}
}
} }
impl Clone for MessageProcessor { impl Clone for MessageProcessor {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -257,6 +274,7 @@ impl Clone for MessageProcessor {
programs: self.programs.clone(), programs: self.programs.clone(),
loaders: self.loaders.clone(), loaders: self.loaders.clone(),
native_loader: NativeLoader::default(), native_loader: NativeLoader::default(),
is_cross_program_supported: self.is_cross_program_supported,
} }
} }
} }
@ -280,6 +298,10 @@ impl MessageProcessor {
} }
} }
pub fn set_cross_program_support(&mut self, is_supported: bool) {
self.is_cross_program_supported = is_supported;
}
/// Create the KeyedAccounts that will be passed to the program /// Create the KeyedAccounts that will be passed to the program
fn create_keyed_accounts<'a>( fn create_keyed_accounts<'a>(
message: &'a Message, message: &'a Message,
@ -357,6 +379,10 @@ impl MessageProcessor {
accounts: &[Rc<RefCell<Account>>], accounts: &[Rc<RefCell<Account>>],
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if !self.is_cross_program_supported {
return Err(InstructionError::ReentrancyNotAllowed);
}
let instruction = &message.instructions[0]; let instruction = &message.instructions[0];
// Verify the calling program hasn't misbehaved // Verify the calling program hasn't misbehaved
@ -511,6 +537,7 @@ impl MessageProcessor {
pre_accounts, pre_accounts,
self.programs.clone(), self.programs.clone(),
log_collector, log_collector,
self.is_cross_program_supported,
); );
let keyed_accounts = let keyed_accounts =
Self::create_keyed_accounts(message, instruction, executable_accounts, accounts)?; Self::create_keyed_accounts(message, instruction, executable_accounts, accounts)?;
@ -583,8 +610,14 @@ mod tests {
true, true,
)) ))
} }
let mut invoke_context = let mut invoke_context = ThisInvokeContext::new(
ThisInvokeContext::new(&program_ids[0], Rent::default(), pre_accounts, vec![], None); &program_ids[0],
Rent::default(),
pre_accounts,
vec![],
None,
true,
);
// Check call depth increases and has a limit // Check call depth increases and has a limit
let mut depth_reached = 1; let mut depth_reached = 1;
@ -1352,6 +1385,7 @@ mod tests {
vec![owned_preaccount, not_owned_preaccount], vec![owned_preaccount, not_owned_preaccount],
vec![], vec![],
None, None,
true,
); );
let metas = vec![ let metas = vec![
AccountMeta::new(owned_key, false), AccountMeta::new(owned_key, false),

View File

@ -209,4 +209,6 @@ pub trait InvokeContext {
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)]; fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
fn log_enabled(&self) -> bool; fn log_enabled(&self) -> bool;
fn log(&mut self, message: &str); fn log(&mut self, message: &str);
/// Are cross program invocations supported
fn is_cross_program_supported(&self) -> bool;
} }