diff --git a/programs/bpf_loader_api/src/lib.rs b/programs/bpf_loader_api/src/lib.rs index f1bfd38d9..029933ade 100644 --- a/programs/bpf_loader_api/src/lib.rs +++ b/programs/bpf_loader_api/src/lib.rs @@ -18,6 +18,7 @@ use log::*; use solana_rbpf::{memory_region::MemoryRegion, EbpfVm}; use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::instruction_processor_utils::limited_deserialize; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::sysvar::rent; @@ -89,7 +90,7 @@ pub fn process_instruction( ) -> Result<(), InstructionError> { solana_logger::setup(); - if let Ok(instruction) = bincode::deserialize(ix_data) { + if let Ok(instruction) = limited_deserialize(ix_data) { match instruction { LoaderInstruction::Write { offset, bytes } => { if keyed_accounts[0].signer_key().is_none() { diff --git a/programs/btc_spv_api/src/spv_processor.rs b/programs/btc_spv_api/src/spv_processor.rs index 1b19aeeca..f9992e037 100644 --- a/programs/btc_spv_api/src/spv_processor.rs +++ b/programs/btc_spv_api/src/spv_processor.rs @@ -8,6 +8,7 @@ use hex; use log::*; use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::instruction_processor_utils::limited_deserialize; use solana_sdk::pubkey::Pubkey; pub struct SpvProcessor {} @@ -103,10 +104,7 @@ pub fn process_instruction( ) -> Result<(), InstructionError> { // solana_logger::setup(); - let command = bincode::deserialize::(data).map_err(|err| { - info!("invalid instruction data: {:?} {:?}", data, err); - InstructionError::InvalidInstructionData - })?; + let command = limited_deserialize::(data)?; trace!("{:?}", command); diff --git a/programs/budget_api/src/budget_processor.rs b/programs/budget_api/src/budget_processor.rs index 682da9eff..f625ade31 100644 --- a/programs/budget_api/src/budget_processor.rs +++ b/programs/budget_api/src/budget_processor.rs @@ -4,11 +4,11 @@ use crate::{ budget_instruction::{BudgetError, BudgetInstruction}, budget_state::BudgetState, }; -use bincode::deserialize; use chrono::prelude::{DateTime, Utc}; use log::*; use solana_sdk::{ - account::KeyedAccount, hash::hash, instruction::InstructionError, pubkey::Pubkey, + account::KeyedAccount, hash::hash, instruction::InstructionError, + instruction_processor_utils::limited_deserialize, pubkey::Pubkey, }; /// Process a Witness Signature. Any payment plans waiting on this signature @@ -106,10 +106,7 @@ pub fn process_instruction( keyed_accounts: &mut [KeyedAccount], data: &[u8], ) -> Result<(), InstructionError> { - let instruction = deserialize(data).map_err(|err| { - info!("Invalid transaction data: {:?} {:?}", data, err); - InstructionError::InvalidInstructionData - })?; + let instruction = limited_deserialize(data)?; trace!("process_instruction: {:?}", instruction); diff --git a/programs/config_api/src/config_processor.rs b/programs/config_api/src/config_processor.rs index f016d2dd0..a2d421e24 100644 --- a/programs/config_api/src/config_processor.rs +++ b/programs/config_api/src/config_processor.rs @@ -5,7 +5,7 @@ use bincode::deserialize; use log::*; use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; -use solana_sdk::instruction_processor_utils::next_keyed_account; +use solana_sdk::instruction_processor_utils::{limited_deserialize, next_keyed_account}; use solana_sdk::pubkey::Pubkey; pub fn process_instruction( @@ -13,11 +13,7 @@ pub fn process_instruction( keyed_accounts: &mut [KeyedAccount], data: &[u8], ) -> Result<(), InstructionError> { - let key_list: ConfigKeys = deserialize(data).map_err(|err| { - error!("Invalid ConfigKeys data: {:?} {:?}", data, err); - InstructionError::InvalidInstructionData - })?; - + let key_list: ConfigKeys = limited_deserialize(data)?; let keyed_accounts_iter = &mut keyed_accounts.iter_mut(); let config_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?; let current_data: ConfigKeys = diff --git a/programs/exchange_api/src/exchange_processor.rs b/programs/exchange_api/src/exchange_processor.rs index 2803c25b4..4b3999408 100644 --- a/programs/exchange_api/src/exchange_processor.rs +++ b/programs/exchange_api/src/exchange_processor.rs @@ -7,6 +7,7 @@ use log::*; use solana_metrics::inc_new_counter_info; use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::instruction_processor_utils::limited_deserialize; use solana_sdk::pubkey::Pubkey; use std::cmp; @@ -432,14 +433,7 @@ pub fn process_instruction( ) -> Result<(), InstructionError> { solana_logger::setup(); - let command = bincode::deserialize::(data).map_err(|err| { - info!("Invalid transaction data: {:?} {:?}", data, err); - InstructionError::InvalidInstructionData - })?; - - trace!("{:?}", command); - - match command { + match limited_deserialize::(data)? { ExchangeInstruction::AccountRequest => { ExchangeProcessor::do_account_request(keyed_accounts) } diff --git a/programs/move_loader_api/src/processor.rs b/programs/move_loader_api/src/processor.rs index 403617f7c..c42a20738 100644 --- a/programs/move_loader_api/src/processor.rs +++ b/programs/move_loader_api/src/processor.rs @@ -6,7 +6,8 @@ use bytecode_verifier::{VerifiedModule, VerifiedScript}; use log::*; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ - account::KeyedAccount, instruction::InstructionError, loader_instruction::LoaderInstruction, + account::KeyedAccount, instruction::InstructionError, + instruction_processor_utils::limited_deserialize, loader_instruction::LoaderInstruction, pubkey::Pubkey, sysvar::rent, }; use types::{ @@ -36,14 +37,7 @@ pub fn process_instruction( ) -> Result<(), InstructionError> { solana_logger::setup(); - let command = bincode::deserialize::(data).map_err(|err| { - info!("Invalid instruction: {:?} {:?}", data, err); - InstructionError::InvalidInstructionData - })?; - - trace!("{:?}", command); - - match command { + match limited_deserialize(data)? { LoaderInstruction::Write { offset, bytes } => { MoveProcessor::do_write(keyed_accounts, offset, &bytes) } @@ -138,7 +132,7 @@ impl MoveProcessor { fn deserialize_compiled_program( data: &[u8], ) -> Result<(CompiledScript, Vec), InstructionError> { - match bincode::deserialize(data).map_err(map_data_error)? { + match limited_deserialize(data)? { LibraAccountState::CompiledProgram(string) => { let program: Program = serde_json::from_str(&string).map_err(map_json_error)?; @@ -163,7 +157,7 @@ impl MoveProcessor { fn deserialize_verified_program( data: &[u8], ) -> Result<(VerifiedScript, Vec), InstructionError> { - match bincode::deserialize(data).map_err(map_data_error)? { + match limited_deserialize(data)? { LibraAccountState::VerifiedProgram { script_bytes, modules_bytes, @@ -234,7 +228,7 @@ impl MoveProcessor { ) -> Result { let mut data_store = DataStore::default(); for keyed_account in keyed_accounts { - match bincode::deserialize(&keyed_account.account.data).map_err(map_data_error)? { + match limited_deserialize(&keyed_account.account.data)? { LibraAccountState::Genesis(write_set) => data_store.apply_write_set(&write_set), LibraAccountState::User(owner, write_set) => { if owner != *genesis_key { @@ -349,7 +343,7 @@ impl MoveProcessor { keyed_accounts: &mut [KeyedAccount], data: &[u8], ) -> Result<(), InstructionError> { - match bincode::deserialize(&data).map_err(map_data_error)? { + match limited_deserialize(&data)? { InvokeCommand::CreateGenesis(amount) => { if keyed_accounts.is_empty() { debug!("Error: Requires an unallocated account"); @@ -360,9 +354,7 @@ impl MoveProcessor { return Err(InstructionError::InvalidArgument); } - match bincode::deserialize(&keyed_accounts[0].account.data) - .map_err(map_data_error)? - { + match limited_deserialize(&keyed_accounts[0].account.data)? { LibraAccountState::Unallocated => Self::serialize_and_enforce_length( &LibraAccountState::create_genesis(amount)?, &mut keyed_accounts[0].account.data, diff --git a/programs/stake_api/src/stake_instruction.rs b/programs/stake_api/src/stake_instruction.rs index dd1b8e554..d38676888 100644 --- a/programs/stake_api/src/stake_instruction.rs +++ b/programs/stake_api/src/stake_instruction.rs @@ -2,14 +2,13 @@ use crate::{ config, id, stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState}, }; -use bincode::deserialize; use log::*; use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::{Deserialize, Serialize}; use solana_sdk::{ account::{get_signers, KeyedAccount}, instruction::{AccountMeta, Instruction, InstructionError}, - instruction_processor_utils::{next_keyed_account, DecodeError}, + instruction_processor_utils::{limited_deserialize, next_keyed_account, DecodeError}, pubkey::Pubkey, system_instruction, sysvar, sysvar::rent, @@ -275,7 +274,7 @@ pub fn process_instruction( let me = &mut next_keyed_account(keyed_accounts)?; // TODO: data-driven unpack and dispatch of KeyedAccounts - match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? { + match limited_deserialize(data)? { StakeInstruction::Initialize(authorized, lockup) => { rent::verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?; me.initialize(&authorized, &lockup) diff --git a/programs/storage_api/src/storage_processor.rs b/programs/storage_api/src/storage_processor.rs index c0f7459b3..722dbc778 100644 --- a/programs/storage_api/src/storage_processor.rs +++ b/programs/storage_api/src/storage_processor.rs @@ -5,6 +5,7 @@ use crate::storage_contract::StorageAccount; use crate::storage_instruction::StorageInstruction; use solana_sdk::account::KeyedAccount; use solana_sdk::instruction::InstructionError; +use solana_sdk::instruction_processor_utils::limited_deserialize; use solana_sdk::pubkey::Pubkey; use solana_sdk::sysvar; @@ -19,7 +20,7 @@ pub fn process_instruction( let me_unsigned = me[0].signer_key().is_none(); let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me[0].account); - match bincode::deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? { + match limited_deserialize(data)? { StorageInstruction::InitializeStorage { owner, account_type, diff --git a/programs/vest_api/Cargo.toml b/programs/vest_api/Cargo.toml index 4d88eee9a..b52a2a2f1 100644 --- a/programs/vest_api/Cargo.toml +++ b/programs/vest_api/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://solana.com/" edition = "2018" [dependencies] -bincode = "1.1.4" +bincode = "1.2.0" chrono = { version = "0.4.9", features = ["serde"] } log = "0.4.8" num-derive = "0.2" diff --git a/programs/vest_api/src/vest_processor.rs b/programs/vest_api/src/vest_processor.rs index 65f8be902..681c268e1 100644 --- a/programs/vest_api/src/vest_processor.rs +++ b/programs/vest_api/src/vest_processor.rs @@ -4,13 +4,12 @@ use crate::{ vest_instruction::{VestError, VestInstruction}, vest_state::VestState, }; -use bincode::deserialize; use chrono::prelude::*; use solana_config_api::get_config_data; use solana_sdk::{ account::{Account, KeyedAccount}, instruction::InstructionError, - instruction_processor_utils::next_keyed_account, + instruction_processor_utils::{limited_deserialize, next_keyed_account}, pubkey::Pubkey, }; @@ -62,7 +61,7 @@ pub fn process_instruction( let keyed_accounts_iter = &mut keyed_accounts.iter_mut(); let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.account; - let instruction = deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)?; + let instruction = limited_deserialize(data)?; let mut vest_state = if let VestInstruction::InitializeAccount { terminator_pubkey, diff --git a/programs/vote_api/src/vote_instruction.rs b/programs/vote_api/src/vote_instruction.rs index 653556a19..4d9167c2f 100644 --- a/programs/vote_api/src/vote_instruction.rs +++ b/programs/vote_api/src/vote_instruction.rs @@ -5,7 +5,6 @@ use crate::{ id, vote_state::{self, Vote, VoteAuthorize, VoteInit, VoteState}, }; -use bincode::deserialize; use log::*; use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::{Deserialize, Serialize}; @@ -13,7 +12,7 @@ use solana_metrics::datapoint_debug; use solana_sdk::{ account::KeyedAccount, instruction::{AccountMeta, Instruction, InstructionError}, - instruction_processor_utils::DecodeError, + instruction_processor_utils::{limited_deserialize, DecodeError}, pubkey::Pubkey, system_instruction, sysvar::{self, rent}, @@ -178,7 +177,7 @@ pub fn process_instruction( let me = &mut me[0]; // TODO: data-driven unpack and dispatch of KeyedAccounts - match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? { + match limited_deserialize(data)? { VoteInstruction::InitializeAccount(vote_init) => { if rest.is_empty() { return Err(InstructionError::InvalidInstructionData); diff --git a/sdk/src/instruction_processor_utils.rs b/sdk/src/instruction_processor_utils.rs index 5474a1f19..338234fd2 100644 --- a/sdk/src/instruction_processor_utils.rs +++ b/sdk/src/instruction_processor_utils.rs @@ -41,6 +41,20 @@ pub fn next_keyed_account(iter: &mut I) -> Result(data: &[u8]) -> Result<(T), InstructionError> +where + T: serde::de::DeserializeOwned, +{ + #[cfg(not(feature = "program"))] + let limit = crate::packet::PACKET_DATA_SIZE as u64; + #[cfg(feature = "program")] + let limit = 1024; + bincode::config() + .limit(limit) + .deserialize(data) + .map_err(|_| InstructionError::InvalidInstructionData) +} + pub trait DecodeError { fn decode_custom_error_to_enum(custom: u32) -> Option where