Limit deserialization of program inputs (#6522)
This commit is contained in:
parent
955d0ab76f
commit
ddefc96433
|
@ -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() {
|
||||
|
|
|
@ -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::<SpvInstruction>(data).map_err(|err| {
|
||||
info!("invalid instruction data: {:?} {:?}", data, err);
|
||||
InstructionError::InvalidInstructionData
|
||||
})?;
|
||||
let command = limited_deserialize::<SpvInstruction>(data)?;
|
||||
|
||||
trace!("{:?}", command);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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::<ExchangeInstruction>(data).map_err(|err| {
|
||||
info!("Invalid transaction data: {:?} {:?}", data, err);
|
||||
InstructionError::InvalidInstructionData
|
||||
})?;
|
||||
|
||||
trace!("{:?}", command);
|
||||
|
||||
match command {
|
||||
match limited_deserialize::<ExchangeInstruction>(data)? {
|
||||
ExchangeInstruction::AccountRequest => {
|
||||
ExchangeProcessor::do_account_request(keyed_accounts)
|
||||
}
|
||||
|
|
|
@ -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::<LoaderInstruction>(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<CompiledModule>), 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<VerifiedModule>), 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<DataStore, InstructionError> {
|
||||
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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -41,6 +41,20 @@ pub fn next_keyed_account<I: Iterator>(iter: &mut I) -> Result<I::Item, Instruct
|
|||
iter.next().ok_or(InstructionError::NotEnoughAccountKeys)
|
||||
}
|
||||
|
||||
pub fn limited_deserialize<T>(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<E> {
|
||||
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
||||
where
|
||||
|
|
Loading…
Reference in New Issue