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_rbpf::{memory_region::MemoryRegion, EbpfVm};
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::instruction::InstructionError;
|
||||||
|
use solana_sdk::instruction_processor_utils::limited_deserialize;
|
||||||
use solana_sdk::loader_instruction::LoaderInstruction;
|
use solana_sdk::loader_instruction::LoaderInstruction;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::sysvar::rent;
|
use solana_sdk::sysvar::rent;
|
||||||
|
@ -89,7 +90,7 @@ pub fn process_instruction(
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
if let Ok(instruction) = bincode::deserialize(ix_data) {
|
if let Ok(instruction) = limited_deserialize(ix_data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
LoaderInstruction::Write { offset, bytes } => {
|
LoaderInstruction::Write { offset, bytes } => {
|
||||||
if keyed_accounts[0].signer_key().is_none() {
|
if keyed_accounts[0].signer_key().is_none() {
|
||||||
|
|
|
@ -8,6 +8,7 @@ use hex;
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::instruction::InstructionError;
|
||||||
|
use solana_sdk::instruction_processor_utils::limited_deserialize;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
|
|
||||||
pub struct SpvProcessor {}
|
pub struct SpvProcessor {}
|
||||||
|
@ -103,10 +104,7 @@ pub fn process_instruction(
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
// solana_logger::setup();
|
// solana_logger::setup();
|
||||||
|
|
||||||
let command = bincode::deserialize::<SpvInstruction>(data).map_err(|err| {
|
let command = limited_deserialize::<SpvInstruction>(data)?;
|
||||||
info!("invalid instruction data: {:?} {:?}", data, err);
|
|
||||||
InstructionError::InvalidInstructionData
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("{:?}", command);
|
trace!("{:?}", command);
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ use crate::{
|
||||||
budget_instruction::{BudgetError, BudgetInstruction},
|
budget_instruction::{BudgetError, BudgetInstruction},
|
||||||
budget_state::BudgetState,
|
budget_state::BudgetState,
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
|
||||||
use chrono::prelude::{DateTime, Utc};
|
use chrono::prelude::{DateTime, Utc};
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_sdk::{
|
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
|
/// Process a Witness Signature. Any payment plans waiting on this signature
|
||||||
|
@ -106,10 +106,7 @@ pub fn process_instruction(
|
||||||
keyed_accounts: &mut [KeyedAccount],
|
keyed_accounts: &mut [KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let instruction = deserialize(data).map_err(|err| {
|
let instruction = limited_deserialize(data)?;
|
||||||
info!("Invalid transaction data: {:?} {:?}", data, err);
|
|
||||||
InstructionError::InvalidInstructionData
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("process_instruction: {:?}", instruction);
|
trace!("process_instruction: {:?}", instruction);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use bincode::deserialize;
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::instruction::InstructionError;
|
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;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
|
@ -13,11 +13,7 @@ pub fn process_instruction(
|
||||||
keyed_accounts: &mut [KeyedAccount],
|
keyed_accounts: &mut [KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let key_list: ConfigKeys = deserialize(data).map_err(|err| {
|
let key_list: ConfigKeys = limited_deserialize(data)?;
|
||||||
error!("Invalid ConfigKeys data: {:?} {:?}", data, err);
|
|
||||||
InstructionError::InvalidInstructionData
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
|
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
|
||||||
let config_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
|
let config_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||||
let current_data: ConfigKeys =
|
let current_data: ConfigKeys =
|
||||||
|
|
|
@ -7,6 +7,7 @@ use log::*;
|
||||||
use solana_metrics::inc_new_counter_info;
|
use solana_metrics::inc_new_counter_info;
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::instruction::InstructionError;
|
||||||
|
use solana_sdk::instruction_processor_utils::limited_deserialize;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
|
@ -432,14 +433,7 @@ pub fn process_instruction(
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
let command = bincode::deserialize::<ExchangeInstruction>(data).map_err(|err| {
|
match limited_deserialize::<ExchangeInstruction>(data)? {
|
||||||
info!("Invalid transaction data: {:?} {:?}", data, err);
|
|
||||||
InstructionError::InvalidInstructionData
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("{:?}", command);
|
|
||||||
|
|
||||||
match command {
|
|
||||||
ExchangeInstruction::AccountRequest => {
|
ExchangeInstruction::AccountRequest => {
|
||||||
ExchangeProcessor::do_account_request(keyed_accounts)
|
ExchangeProcessor::do_account_request(keyed_accounts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ use bytecode_verifier::{VerifiedModule, VerifiedScript};
|
||||||
use log::*;
|
use log::*;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
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,
|
pubkey::Pubkey, sysvar::rent,
|
||||||
};
|
};
|
||||||
use types::{
|
use types::{
|
||||||
|
@ -36,14 +37,7 @@ pub fn process_instruction(
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
let command = bincode::deserialize::<LoaderInstruction>(data).map_err(|err| {
|
match limited_deserialize(data)? {
|
||||||
info!("Invalid instruction: {:?} {:?}", data, err);
|
|
||||||
InstructionError::InvalidInstructionData
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!("{:?}", command);
|
|
||||||
|
|
||||||
match command {
|
|
||||||
LoaderInstruction::Write { offset, bytes } => {
|
LoaderInstruction::Write { offset, bytes } => {
|
||||||
MoveProcessor::do_write(keyed_accounts, offset, &bytes)
|
MoveProcessor::do_write(keyed_accounts, offset, &bytes)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +132,7 @@ impl MoveProcessor {
|
||||||
fn deserialize_compiled_program(
|
fn deserialize_compiled_program(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> {
|
) -> Result<(CompiledScript, Vec<CompiledModule>), InstructionError> {
|
||||||
match bincode::deserialize(data).map_err(map_data_error)? {
|
match limited_deserialize(data)? {
|
||||||
LibraAccountState::CompiledProgram(string) => {
|
LibraAccountState::CompiledProgram(string) => {
|
||||||
let program: Program = serde_json::from_str(&string).map_err(map_json_error)?;
|
let program: Program = serde_json::from_str(&string).map_err(map_json_error)?;
|
||||||
|
|
||||||
|
@ -163,7 +157,7 @@ impl MoveProcessor {
|
||||||
fn deserialize_verified_program(
|
fn deserialize_verified_program(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(VerifiedScript, Vec<VerifiedModule>), InstructionError> {
|
) -> Result<(VerifiedScript, Vec<VerifiedModule>), InstructionError> {
|
||||||
match bincode::deserialize(data).map_err(map_data_error)? {
|
match limited_deserialize(data)? {
|
||||||
LibraAccountState::VerifiedProgram {
|
LibraAccountState::VerifiedProgram {
|
||||||
script_bytes,
|
script_bytes,
|
||||||
modules_bytes,
|
modules_bytes,
|
||||||
|
@ -234,7 +228,7 @@ impl MoveProcessor {
|
||||||
) -> Result<DataStore, InstructionError> {
|
) -> Result<DataStore, InstructionError> {
|
||||||
let mut data_store = DataStore::default();
|
let mut data_store = DataStore::default();
|
||||||
for keyed_account in keyed_accounts {
|
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::Genesis(write_set) => data_store.apply_write_set(&write_set),
|
||||||
LibraAccountState::User(owner, write_set) => {
|
LibraAccountState::User(owner, write_set) => {
|
||||||
if owner != *genesis_key {
|
if owner != *genesis_key {
|
||||||
|
@ -349,7 +343,7 @@ impl MoveProcessor {
|
||||||
keyed_accounts: &mut [KeyedAccount],
|
keyed_accounts: &mut [KeyedAccount],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
match bincode::deserialize(&data).map_err(map_data_error)? {
|
match limited_deserialize(&data)? {
|
||||||
InvokeCommand::CreateGenesis(amount) => {
|
InvokeCommand::CreateGenesis(amount) => {
|
||||||
if keyed_accounts.is_empty() {
|
if keyed_accounts.is_empty() {
|
||||||
debug!("Error: Requires an unallocated account");
|
debug!("Error: Requires an unallocated account");
|
||||||
|
@ -360,9 +354,7 @@ impl MoveProcessor {
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
match bincode::deserialize(&keyed_accounts[0].account.data)
|
match limited_deserialize(&keyed_accounts[0].account.data)? {
|
||||||
.map_err(map_data_error)?
|
|
||||||
{
|
|
||||||
LibraAccountState::Unallocated => Self::serialize_and_enforce_length(
|
LibraAccountState::Unallocated => Self::serialize_and_enforce_length(
|
||||||
&LibraAccountState::create_genesis(amount)?,
|
&LibraAccountState::create_genesis(amount)?,
|
||||||
&mut keyed_accounts[0].account.data,
|
&mut keyed_accounts[0].account.data,
|
||||||
|
|
|
@ -2,14 +2,13 @@ use crate::{
|
||||||
config, id,
|
config, id,
|
||||||
stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState},
|
stake_state::{Authorized, Lockup, StakeAccount, StakeAuthorize, StakeState},
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{get_signers, KeyedAccount},
|
account::{get_signers, KeyedAccount},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
instruction_processor_utils::{next_keyed_account, DecodeError},
|
instruction_processor_utils::{limited_deserialize, next_keyed_account, DecodeError},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction, sysvar,
|
system_instruction, sysvar,
|
||||||
sysvar::rent,
|
sysvar::rent,
|
||||||
|
@ -275,7 +274,7 @@ pub fn process_instruction(
|
||||||
let me = &mut next_keyed_account(keyed_accounts)?;
|
let me = &mut next_keyed_account(keyed_accounts)?;
|
||||||
|
|
||||||
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
||||||
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
match limited_deserialize(data)? {
|
||||||
StakeInstruction::Initialize(authorized, lockup) => {
|
StakeInstruction::Initialize(authorized, lockup) => {
|
||||||
rent::verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?;
|
rent::verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?;
|
||||||
me.initialize(&authorized, &lockup)
|
me.initialize(&authorized, &lockup)
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::storage_contract::StorageAccount;
|
||||||
use crate::storage_instruction::StorageInstruction;
|
use crate::storage_instruction::StorageInstruction;
|
||||||
use solana_sdk::account::KeyedAccount;
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::instruction::InstructionError;
|
||||||
|
use solana_sdk::instruction_processor_utils::limited_deserialize;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::sysvar;
|
use solana_sdk::sysvar;
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ pub fn process_instruction(
|
||||||
let me_unsigned = me[0].signer_key().is_none();
|
let me_unsigned = me[0].signer_key().is_none();
|
||||||
let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me[0].account);
|
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 {
|
StorageInstruction::InitializeStorage {
|
||||||
owner,
|
owner,
|
||||||
account_type,
|
account_type,
|
||||||
|
|
|
@ -9,7 +9,7 @@ homepage = "https://solana.com/"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bincode = "1.1.4"
|
bincode = "1.2.0"
|
||||||
chrono = { version = "0.4.9", features = ["serde"] }
|
chrono = { version = "0.4.9", features = ["serde"] }
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
num-derive = "0.2"
|
num-derive = "0.2"
|
||||||
|
|
|
@ -4,13 +4,12 @@ use crate::{
|
||||||
vest_instruction::{VestError, VestInstruction},
|
vest_instruction::{VestError, VestInstruction},
|
||||||
vest_state::VestState,
|
vest_state::VestState,
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use solana_config_api::get_config_data;
|
use solana_config_api::get_config_data;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{Account, KeyedAccount},
|
account::{Account, KeyedAccount},
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
instruction_processor_utils::next_keyed_account,
|
instruction_processor_utils::{limited_deserialize, next_keyed_account},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ pub fn process_instruction(
|
||||||
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
|
let keyed_accounts_iter = &mut keyed_accounts.iter_mut();
|
||||||
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.account;
|
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 {
|
let mut vest_state = if let VestInstruction::InitializeAccount {
|
||||||
terminator_pubkey,
|
terminator_pubkey,
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::{
|
||||||
id,
|
id,
|
||||||
vote_state::{self, Vote, VoteAuthorize, VoteInit, VoteState},
|
vote_state::{self, Vote, VoteAuthorize, VoteInit, VoteState},
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -13,7 +12,7 @@ use solana_metrics::datapoint_debug;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::KeyedAccount,
|
account::KeyedAccount,
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
instruction_processor_utils::DecodeError,
|
instruction_processor_utils::{limited_deserialize, DecodeError},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction,
|
system_instruction,
|
||||||
sysvar::{self, rent},
|
sysvar::{self, rent},
|
||||||
|
@ -178,7 +177,7 @@ pub fn process_instruction(
|
||||||
let me = &mut me[0];
|
let me = &mut me[0];
|
||||||
|
|
||||||
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
// TODO: data-driven unpack and dispatch of KeyedAccounts
|
||||||
match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
|
match limited_deserialize(data)? {
|
||||||
VoteInstruction::InitializeAccount(vote_init) => {
|
VoteInstruction::InitializeAccount(vote_init) => {
|
||||||
if rest.is_empty() {
|
if rest.is_empty() {
|
||||||
return Err(InstructionError::InvalidInstructionData);
|
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)
|
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> {
|
pub trait DecodeError<E> {
|
||||||
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
fn decode_custom_error_to_enum(custom: u32) -> Option<E>
|
||||||
where
|
where
|
||||||
|
|
Loading…
Reference in New Issue