Limit deserialization of program inputs (#6522)

This commit is contained in:
Jack May 2019-10-23 19:56:07 -07:00 committed by GitHub
parent 955d0ab76f
commit ddefc96433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 42 additions and 52 deletions

View File

@ -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() {

View File

@ -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);

View File

@ -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);

View File

@ -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 =

View File

@ -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)
}

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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"

View File

@ -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,

View File

@ -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);

View File

@ -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