From 5dc4410d58f4442b297df53fb3f9a848b21e1e88 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2020 05:50:47 +0000 Subject: [PATCH] Disable cross-program invocations for OperatingMode::Stable (bp #11272) (#11280) * Disable cross-program invocations for OperatingMode::Stable (#11272) (cherry picked from commit 2dbed80e4891b1a37a59bfc2f1376b2f6acc89dc) # 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 --- genesis-programs/src/lib.rs | 1 + programs/bpf/benches/bpf_loader.rs | 3 +++ programs/bpf/tests/programs.rs | 3 ++- programs/bpf_loader/src/lib.rs | 3 +++ programs/bpf_loader/src/syscalls.rs | 1 + runtime/src/bank.rs | 8 ++++++ runtime/src/message_processor.rs | 42 ++++++++++++++++++++++++++--- sdk/src/entrypoint_native.rs | 2 ++ 8 files changed, 58 insertions(+), 5 deletions(-) diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs index cb9dbd530c..3573f7361d 100644 --- a/genesis-programs/src/lib.rs +++ b/genesis-programs/src/lib.rs @@ -107,6 +107,7 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch bank.add_native_program(name, program_id); } } + bank.set_cross_program_support(OperatingMode::Stable != operating_mode); }) } diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index b1729beff7..19e58d740d 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -159,4 +159,7 @@ impl InvokeContext for MockInvokeContext { false } fn log(&mut self, _message: &str) {} + fn is_cross_program_supported(&self) -> bool { + true + } } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 9530af9766..ba8555691a 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -356,7 +356,8 @@ mod bpf { let derived_key2 = Pubkey::create_program_address(&[b"Lil'", b"Bits"], &invoked_program_id).unwrap(); 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 account_metas = vec![ diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 3f445b7f5c..75f7256fc0 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -295,6 +295,9 @@ mod tests { info!("[MockInvokeContext::log] {}", message); self.log.push(message.to_string()); } + fn is_cross_program_supported(&self) -> bool { + true + } } #[rustversion::since(1.46.0)] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index da20459117..47bee788ec 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -825,6 +825,7 @@ fn call<'a>( message_processor.add_program(*program_id, *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)] match message_processor.process_cross_program_instruction( diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 31f8aa0d6e..9267a0c018 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -373,6 +373,9 @@ impl Bank { bank.update_rent(); bank.update_epoch_schedule(); bank.update_recent_blockhashes(); + if bank.operating_mode == Some(OperatingMode::Stable) { + bank.message_processor.set_cross_program_support(false); + } bank } @@ -977,6 +980,11 @@ impl Bank { 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. pub fn last_blockhash(&self) -> Hash { self.blockhash_queue.read().unwrap().last_hash() diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index f94bbec7c6..4ef0779845 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -161,6 +161,7 @@ pub struct ThisInvokeContext<'a> { pub pre_accounts: Vec, pub programs: Vec<(Pubkey, ProcessInstruction)>, pub log_collector: Option<&'a LogCollector>, + is_cross_program_supported: bool, } impl<'a> ThisInvokeContext<'a> { @@ -171,6 +172,7 @@ impl<'a> ThisInvokeContext<'a> { pre_accounts: Vec, programs: Vec<(Pubkey, ProcessInstruction)>, log_collector: Option<&'a LogCollector>, + is_cross_program_supported: bool, ) -> Self { let mut program_ids = Vec::with_capacity(Self::MAX_INVOCATION_DEPTH); program_ids.push(*program_id); @@ -180,6 +182,7 @@ impl<'a> ThisInvokeContext<'a> { pre_accounts, programs, log_collector, + is_cross_program_supported, } } } @@ -226,7 +229,6 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] { &self.programs } - fn log_enabled(&self) -> bool { log_enabled!(log::Level::Info) || self.log_collector.is_some() } @@ -237,12 +239,15 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { log_collector.log(message); } } + fn is_cross_program_supported(&self) -> bool { + self.is_cross_program_supported + } } pub type ProcessInstructionWithContext = fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; -#[derive(Default, Deserialize, Serialize)] +#[derive(Deserialize, Serialize)] pub struct MessageProcessor { #[serde(skip)] programs: Vec<(Pubkey, ProcessInstruction)>, @@ -250,6 +255,18 @@ pub struct MessageProcessor { loaders: Vec<(Pubkey, ProcessInstructionWithContext)>, #[serde(skip)] 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 { fn clone(&self) -> Self { @@ -257,6 +274,7 @@ impl Clone for MessageProcessor { programs: self.programs.clone(), loaders: self.loaders.clone(), 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 fn create_keyed_accounts<'a>( message: &'a Message, @@ -357,6 +379,10 @@ impl MessageProcessor { accounts: &[Rc>], invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { + if !self.is_cross_program_supported { + return Err(InstructionError::ReentrancyNotAllowed); + } + let instruction = &message.instructions[0]; // Verify the calling program hasn't misbehaved @@ -511,6 +537,7 @@ impl MessageProcessor { pre_accounts, self.programs.clone(), log_collector, + self.is_cross_program_supported, ); let keyed_accounts = Self::create_keyed_accounts(message, instruction, executable_accounts, accounts)?; @@ -583,8 +610,14 @@ mod tests { true, )) } - let mut invoke_context = - ThisInvokeContext::new(&program_ids[0], Rent::default(), pre_accounts, vec![], None); + let mut invoke_context = ThisInvokeContext::new( + &program_ids[0], + Rent::default(), + pre_accounts, + vec![], + None, + true, + ); // Check call depth increases and has a limit let mut depth_reached = 1; @@ -1352,6 +1385,7 @@ mod tests { vec![owned_preaccount, not_owned_preaccount], vec![], None, + true, ); let metas = vec![ AccountMeta::new(owned_key, false), diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 4e0c63e722..168d888797 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -209,4 +209,6 @@ pub trait InvokeContext { fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)]; fn log_enabled(&self) -> bool; fn log(&mut self, message: &str); + /// Are cross program invocations supported + fn is_cross_program_supported(&self) -> bool; }