Move loader enforces account size (#6379)

* Move loader enforces account size

* Fix librapay test
This commit is contained in:
Jack May 2019-10-15 18:30:45 -07:00 committed by GitHub
parent 2ee05f1234
commit 78d5c1de9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 23 deletions

View File

@ -75,7 +75,7 @@ pub fn create_accounts(
&from.pubkey(), &from.pubkey(),
to, to,
lamports, lamports,
128, 200,
&solana_move_loader_api::id(), &solana_move_loader_api::id(),
) )
}) })

View File

@ -53,7 +53,7 @@ pub enum LibraAccountState {
} }
impl LibraAccountState { impl LibraAccountState {
pub fn create_unallocated() -> Self { pub fn create_unallocated() -> Self {
LibraAccountState::Unallocated Self::Unallocated
} }
pub fn create_program( pub fn create_program(
@ -66,7 +66,7 @@ impl LibraAccountState {
let mut extra_deps: Vec<VerifiedModule> = vec![]; let mut extra_deps: Vec<VerifiedModule> = vec![];
for dep in deps { for dep in deps {
let state: Self = bincode::deserialize(&dep).unwrap(); let state: Self = bincode::deserialize(&dep).unwrap();
if let LibraAccountState::User(_, write_set) = state { if let Self::User(_, write_set) = state {
for (_, write_op) in write_set.iter() { for (_, write_op) in write_set.iter() {
if let WriteOp::Value(raw_bytes) = write_op { if let WriteOp::Value(raw_bytes) = write_op {
extra_deps.push( extra_deps.push(
@ -99,13 +99,13 @@ impl LibraAccountState {
.expect("Unable to serialize module"); .expect("Unable to serialize module");
modules_bytes.push(buf); modules_bytes.push(buf);
} }
LibraAccountState::CompiledProgram( Self::CompiledProgram(
serde_json::to_string(&Program::new(script_bytes, modules_bytes, vec![])).unwrap(), serde_json::to_string(&Program::new(script_bytes, modules_bytes, vec![])).unwrap(),
) )
} }
pub fn create_user(owner: &Pubkey, write_set: WriteSet) -> Self { pub fn create_user(owner: &Pubkey, write_set: WriteSet) -> Self {
LibraAccountState::User(*owner, write_set) Self::User(*owner, write_set)
} }
pub fn create_genesis(mint_balance: u64) -> Result<(Self), InstructionError> { pub fn create_genesis(mint_balance: u64) -> Result<(Self), InstructionError> {
@ -172,6 +172,6 @@ impl LibraAccountState {
.freeze() .freeze()
.map_err(map_failure_error)?; .map_err(map_failure_error)?;
Ok(LibraAccountState::Genesis(write_set)) Ok(Self::Genesis(write_set))
} }
} }

View File

@ -23,7 +23,10 @@ pub fn map_vm_binary_error(err: vm::errors::BinaryError) -> InstructionError {
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionError { pub fn map_data_error(err: std::boxed::Box<bincode::ErrorKind>) -> InstructionError {
debug!("Error: Account data: {:?}", err); debug!("Error: Account data: {:?}", err);
InstructionError::InvalidAccountData match err.as_ref() {
bincode::ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
_ => InstructionError::InvalidAccountData,
}
} }
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn map_json_error(err: serde_json::error::Error) -> InstructionError { pub fn map_json_error(err: serde_json::error::Error) -> InstructionError {

View File

@ -95,6 +95,22 @@ impl MoveProcessor {
locals locals
} }
fn serialize_and_enforce_length(
state: &LibraAccountState,
data: &mut Vec<u8>,
) -> Result<(), InstructionError> {
let original_len = data.len() as u64;
let mut writer = std::io::Cursor::new(data);
bincode::config()
.limit(original_len)
.serialize_into(&mut writer, &state)
.map_err(map_data_error)?;
if writer.position() < original_len {
writer.set_position(original_len);
}
Ok(())
}
fn serialize_verified_program( fn serialize_verified_program(
script: &VerifiedScript, script: &VerifiedScript,
modules: &[VerifiedModule], modules: &[VerifiedModule],
@ -172,7 +188,7 @@ impl MoveProcessor {
fn execute( fn execute(
sender_address: AccountAddress, sender_address: AccountAddress,
function_name: String, function_name: &str,
args: Vec<TransactionArgument>, args: Vec<TransactionArgument>,
script: VerifiedScript, script: VerifiedScript,
modules: Vec<VerifiedModule>, modules: Vec<VerifiedModule>,
@ -247,20 +263,20 @@ impl MoveProcessor {
let write_set = write_sets let write_set = write_sets
.remove(&AccountAddress::default()) .remove(&AccountAddress::default())
.ok_or_else(Self::missing_account)?; .ok_or_else(Self::missing_account)?;
keyed_accounts[GENESIS_INDEX].account.data.clear(); Self::serialize_and_enforce_length(
let writer = std::io::BufWriter::new(&mut keyed_accounts[GENESIS_INDEX].account.data); &LibraAccountState::Genesis(write_set),
bincode::serialize_into(writer, &LibraAccountState::Genesis(write_set)) &mut keyed_accounts[GENESIS_INDEX].account.data,
.map_err(map_data_error)?; )?;
// Now do the rest of the accounts // Now do the rest of the accounts
for keyed_account in keyed_accounts[GENESIS_INDEX + 1..].iter_mut() { for keyed_account in keyed_accounts[GENESIS_INDEX + 1..].iter_mut() {
let write_set = write_sets let write_set = write_sets
.remove(&pubkey_to_address(keyed_account.unsigned_key())) .remove(&pubkey_to_address(keyed_account.unsigned_key()))
.ok_or_else(Self::missing_account)?; .ok_or_else(Self::missing_account)?;
keyed_account.account.data.clear(); Self::serialize_and_enforce_length(
let writer = std::io::BufWriter::new(&mut keyed_account.account.data); &LibraAccountState::User(genesis_key, write_set),
bincode::serialize_into(writer, &LibraAccountState::User(genesis_key, write_set)) &mut keyed_account.account.data,
.map_err(map_data_error)?; )?;
} }
if !write_sets.is_empty() { if !write_sets.is_empty() {
debug!("Error: Missing keyed accounts"); debug!("Error: Missing keyed accounts");
@ -345,12 +361,10 @@ impl MoveProcessor {
match bincode::deserialize(&keyed_accounts[0].account.data) match bincode::deserialize(&keyed_accounts[0].account.data)
.map_err(map_data_error)? .map_err(map_data_error)?
{ {
LibraAccountState::Unallocated => { LibraAccountState::Unallocated => Self::serialize_and_enforce_length(
keyed_accounts[0].account.data.clear(); &LibraAccountState::create_genesis(amount)?,
let writer = std::io::BufWriter::new(&mut keyed_accounts[0].account.data); &mut keyed_accounts[0].account.data,
bincode::serialize_into(writer, &LibraAccountState::create_genesis(amount)?) ),
.map_err(map_data_error)
}
_ => { _ => {
debug!("Error: Must provide an unallocated account"); debug!("Error: Must provide an unallocated account");
Err(InstructionError::InvalidArgument) Err(InstructionError::InvalidArgument)
@ -385,7 +399,7 @@ impl MoveProcessor {
let output = Self::execute( let output = Self::execute(
sender_address, sender_address,
function_name, &function_name,
args, args,
verified_script, verified_script,
verified_modules, verified_modules,
@ -410,6 +424,34 @@ mod tests {
use solana_sdk::rent_calculator::RentCalculator; use solana_sdk::rent_calculator::RentCalculator;
use solana_sdk::sysvar::rent; use solana_sdk::sysvar::rent;
const BIG_ENOUGH: usize = 6_000;
#[test]
fn test_account_size() {
let mut data =
vec![0_u8; bincode::serialized_size(&LibraAccountState::Unallocated).unwrap() as usize];
let len = data.len();
assert_eq!(
MoveProcessor::serialize_and_enforce_length(&LibraAccountState::Unallocated, &mut data),
Ok(())
);
assert_eq!(len, data.len());
data.resize(6000, 0);
let len = data.len();
assert_eq!(
MoveProcessor::serialize_and_enforce_length(&LibraAccountState::Unallocated, &mut data),
Ok(())
);
assert_eq!(len, data.len());
data.resize(1, 0);
assert_eq!(
MoveProcessor::serialize_and_enforce_length(&LibraAccountState::Unallocated, &mut data),
Err(InstructionError::AccountDataTooSmall)
);
}
#[test] #[test]
fn test_finalize() { fn test_finalize() {
solana_logger::setup(); solana_logger::setup();
@ -439,6 +481,7 @@ mod tests {
false, false,
&mut unallocated.account, &mut unallocated.account,
)]; )];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
&bincode::serialize(&InvokeCommand::CreateGenesis(amount)).unwrap(), &bincode::serialize(&InvokeCommand::CreateGenesis(amount)).unwrap(),
@ -584,6 +627,7 @@ mod tests {
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&rent_id, false, &mut rent_account), KeyedAccount::new(&rent_id, false, &mut rent_account),
]; ];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
@ -593,6 +637,8 @@ mod tests {
KeyedAccount::new(&sender.key, false, &mut sender.account), KeyedAccount::new(&sender.key, false, &mut sender.account),
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
keyed_accounts[2].account.data.resize(BIG_ENOUGH, 0);
keyed_accounts[3].account.data.resize(BIG_ENOUGH, 0);
let amount = 2; let amount = 2;
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
@ -656,6 +702,7 @@ mod tests {
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&rent_id, false, &mut rent_account), KeyedAccount::new(&rent_id, false, &mut rent_account),
]; ];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
@ -664,6 +711,7 @@ mod tests {
KeyedAccount::new(&genesis.key, false, &mut genesis.account), KeyedAccount::new(&genesis.key, false, &mut genesis.account),
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
keyed_accounts[2].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
@ -700,6 +748,7 @@ mod tests {
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&rent_id, false, &mut rent_account), KeyedAccount::new(&rent_id, false, &mut rent_account),
]; ];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
@ -708,6 +757,7 @@ mod tests {
KeyedAccount::new(&genesis.key, false, &mut genesis.account), KeyedAccount::new(&genesis.key, false, &mut genesis.account),
KeyedAccount::new(&module.key, false, &mut module.account), KeyedAccount::new(&module.key, false, &mut module.account),
]; ];
keyed_accounts[2].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,
@ -784,6 +834,7 @@ mod tests {
KeyedAccount::new(&program.key, true, &mut program.account), KeyedAccount::new(&program.key, true, &mut program.account),
KeyedAccount::new(&rent_id, false, &mut rent_account), KeyedAccount::new(&rent_id, false, &mut rent_account),
]; ];
keyed_accounts[0].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_finalize(&mut keyed_accounts).unwrap(); MoveProcessor::do_finalize(&mut keyed_accounts).unwrap();
@ -792,6 +843,7 @@ mod tests {
KeyedAccount::new(&genesis.key, false, &mut genesis.account), KeyedAccount::new(&genesis.key, false, &mut genesis.account),
KeyedAccount::new(&payee.key, false, &mut payee.account), KeyedAccount::new(&payee.key, false, &mut payee.account),
]; ];
keyed_accounts[2].account.data.resize(BIG_ENOUGH, 0);
MoveProcessor::do_invoke_main( MoveProcessor::do_invoke_main(
&mut keyed_accounts, &mut keyed_accounts,