deny slice indexing (#23565)

This commit is contained in:
Jack May 2022-03-10 11:48:33 -08:00 committed by GitHub
parent ead8cc4366
commit ddd9d5a5a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 274 additions and 110 deletions

View File

@ -1,3 +1,6 @@
#![deny(clippy::integer_arithmetic)]
#![deny(clippy::indexing_slicing)]
pub mod alloc;
pub mod allocator_bump;
pub mod deprecated;
@ -141,7 +144,10 @@ pub fn create_executor(
create_executor_metrics.program_id = programdata.get_key().to_string();
let mut load_elf_time = Measure::start("load_elf_time");
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf(
&programdata.get_data()[programdata_offset..],
programdata
.get_data()
.get(programdata_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?,
None,
config,
syscall_registry,
@ -192,7 +198,7 @@ fn write_program_data<'a>(
) -> Result<(), InstructionError> {
let data = program.get_data_mut();
let write_offset = program_data_offset.saturating_add(bytes.len());
if data.len() < write_offset {
if data.len() < write_offset || (program_data_offset..write_offset).len() != bytes.len() {
ic_logger_msg!(
log_collector,
"Write overflow: {} < {}",
@ -201,7 +207,9 @@ fn write_program_data<'a>(
);
return Err(InstructionError::AccountDataTooSmall);
}
data[program_data_offset..write_offset].copy_from_slice(bytes);
data.get_mut(program_data_offset..write_offset)
.ok_or(InstructionError::AccountDataTooSmall)?
.copy_from_slice(bytes);
Ok(())
}
@ -695,9 +703,22 @@ fn process_loader_upgradeable_instruction(
slot: clock.slot,
upgrade_authority_address,
})?;
programdata.get_data_mut()[programdata_data_offset
..programdata_data_offset.saturating_add(buffer_data_len)]
.copy_from_slice(&buffer.get_data()[buffer_data_offset..]);
let to_slice = programdata
.get_data_mut()
.get_mut(
programdata_data_offset
..programdata_data_offset.saturating_add(buffer_data_len),
)
.ok_or(InstructionError::AccountDataTooSmall)?;
let from_slice = buffer
.get_data()
.get(buffer_data_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?;
if to_slice.len() != from_slice.len() {
return Err(InstructionError::AccountDataTooSmall);
}
to_slice.copy_from_slice(from_slice);
}
// Update the Program account
@ -895,10 +916,25 @@ fn process_loader_upgradeable_instruction(
slot: clock.slot,
upgrade_authority_address: current_upgrade_authority_address,
})?;
programdata.get_data_mut()
[programdata_data_offset..programdata_data_offset.saturating_add(buffer_data_len)]
.copy_from_slice(&buffer.get_data()[buffer_data_offset..]);
programdata.get_data_mut()[programdata_data_offset.saturating_add(buffer_data_len)..]
let to_slice = programdata
.get_data_mut()
.get_mut(
programdata_data_offset
..programdata_data_offset.saturating_add(buffer_data_len),
)
.ok_or(InstructionError::AccountDataTooSmall)?;
let from_slice = buffer
.get_data()
.get(buffer_data_offset..)
.ok_or(InstructionError::AccountDataTooSmall)?;
if to_slice.len() != from_slice.len() {
return Err(InstructionError::AccountDataTooSmall);
}
to_slice.copy_from_slice(from_slice);
programdata
.get_data_mut()
.get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
.ok_or(InstructionError::AccountDataTooSmall)?
.fill(0);
// Fund ProgramData to rent-exemption, spill the rest
@ -1555,7 +1591,7 @@ mod tests {
}],
Ok(()),
);
assert_eq!(&vec![0, 0, 0, 1, 2, 3], accounts[0].data());
assert_eq!(&vec![0, 0, 0, 1, 2, 3], accounts.first().unwrap().data());
// Case: Overflow
program_account.set_data(vec![0; 5]);
@ -1619,10 +1655,10 @@ mod tests {
}],
Ok(()),
);
assert!(accounts[0].executable());
assert!(accounts.first().unwrap().executable());
// Case: Finalize bad ELF
program_account.data_as_mut_slice()[0] = 0;
*program_account.data_as_mut_slice().get_mut(0).unwrap() = 0;
process_instruction(
&loader_id,
&[],
@ -1856,7 +1892,7 @@ mod tests {
instruction_accounts.clone(),
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -1870,13 +1906,13 @@ mod tests {
&[],
&instruction_data,
vec![
(buffer_address, accounts[0].clone()),
(authority_address, accounts[1].clone()),
(buffer_address, accounts.first().unwrap().clone()),
(authority_address, accounts.get(1).unwrap().clone()),
],
instruction_accounts,
Err(InstructionError::AccountAlreadyInitialized),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -1941,7 +1977,7 @@ mod tests {
instruction_accounts.clone(),
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -1949,7 +1985,12 @@ mod tests {
}
);
assert_eq!(
&accounts[0].data()[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
&accounts
.first()
.unwrap()
.data()
.get(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap(),
&[42; 9]
);
@ -1977,7 +2018,7 @@ mod tests {
instruction_accounts.clone(),
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -1985,7 +2026,12 @@ mod tests {
}
);
assert_eq!(
&accounts[0].data()[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
&accounts
.first()
.unwrap()
.data()
.get(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap(),
&[0, 0, 0, 42, 42, 42, 42, 42, 42]
);
@ -2173,7 +2219,10 @@ mod tests {
authority_address: Some(upgrade_authority_keypair.pubkey()),
})
.unwrap();
account.data_as_mut_slice()[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap()
.copy_from_slice(&elf);
account
};
@ -2259,12 +2308,14 @@ mod tests {
upgrade_authority_address: Some(upgrade_authority_keypair.pubkey())
}
);
for (i, byte) in post_programdata_account.data()
[UpgradeableLoaderState::programdata_data_offset().unwrap()..]
for (i, byte) in post_programdata_account
.data()
.get(UpgradeableLoaderState::programdata_data_offset().unwrap()..)
.unwrap()
.iter()
.enumerate()
{
assert_eq!(elf[i], *byte);
assert_eq!(*elf.get(i).unwrap(), *byte);
}
// Invoke deployed program
@ -2470,7 +2521,7 @@ mod tests {
elf.len(),
)
.unwrap();
instructions[0] = system_instruction::create_account(
*instructions.get_mut(0).unwrap() = system_instruction::create_account(
&mint_keypair.pubkey(),
&program_keypair.pubkey(),
min_program_balance,
@ -2503,7 +2554,7 @@ mod tests {
elf.len(),
)
.unwrap();
instructions[0] = system_instruction::create_account(
*instructions.get_mut(0).unwrap() = system_instruction::create_account(
&mint_keypair.pubkey(),
&program_keypair.pubkey(),
min_program_balance,
@ -2635,7 +2686,12 @@ mod tests {
elf.len(),
)
.unwrap();
instructions[1].accounts[6] = AccountMeta::new_readonly(Pubkey::new_unique(), false);
*instructions
.get_mut(1)
.unwrap()
.accounts
.get_mut(6)
.unwrap() = AccountMeta::new_readonly(Pubkey::new_unique(), false);
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
assert_eq!(
TransactionError::InstructionError(1, InstructionError::MissingAccount),
@ -2693,8 +2749,10 @@ mod tests {
authority_address: Some(upgrade_authority_keypair.pubkey()),
})
.unwrap();
modified_buffer_account.data_as_mut_slice()
[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
modified_buffer_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap()
.copy_from_slice(&elf);
truncate_data(&mut modified_buffer_account, 5);
bank.store_account(&buffer_address, &modified_buffer_account);
@ -2735,8 +2793,10 @@ mod tests {
authority_address: Some(buffer_address),
})
.unwrap();
modified_buffer_account.data_as_mut_slice()
[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
modified_buffer_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap()
.copy_from_slice(&elf);
bank.store_account(&buffer_address, &modified_buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
@ -2776,8 +2836,10 @@ mod tests {
authority_address: None,
})
.unwrap();
modified_buffer_account.data_as_mut_slice()
[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
modified_buffer_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap()
.copy_from_slice(&elf);
bank.store_account(&buffer_address, &modified_buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
@ -2847,8 +2909,10 @@ mod tests {
authority_address: Some(*buffer_authority),
})
.unwrap();
buffer_account.data_as_mut_slice()
[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
buffer_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::buffer_data_offset().unwrap()..)
.unwrap()
.copy_from_slice(elf_new);
let mut programdata_account = AccountSharedData::new(
min_programdata_balance,
@ -2958,10 +3022,13 @@ mod tests {
let min_programdata_balance = Rent::default().minimum_balance(
UpgradeableLoaderState::programdata_len(elf_orig.len().max(elf_new.len())).unwrap(),
);
assert_eq!(min_programdata_balance, accounts[0].lamports());
assert_eq!(0, accounts[2].lamports());
assert_eq!(1, accounts[3].lamports());
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
assert_eq!(
min_programdata_balance,
accounts.first().unwrap().lamports()
);
assert_eq!(0, accounts.get(2).unwrap().lamports());
assert_eq!(1, accounts.get(3).unwrap().lamports());
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::ProgramData {
@ -2969,13 +3036,19 @@ mod tests {
upgrade_authority_address: Some(upgrade_authority_address)
}
);
for (i, byte) in accounts[0].data()[UpgradeableLoaderState::programdata_data_offset()
for (i, byte) in accounts
.first()
.unwrap()
.data()
.get(
UpgradeableLoaderState::programdata_data_offset().unwrap()
..UpgradeableLoaderState::programdata_data_offset().unwrap() + elf_new.len(),
)
.unwrap()
..UpgradeableLoaderState::programdata_data_offset().unwrap() + elf_new.len()]
.iter()
.enumerate()
{
assert_eq!(elf_new[i], *byte);
assert_eq!(*elf_new.get(i).unwrap(), *byte);
}
// Case: not upgradable
@ -2986,7 +3059,9 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[0]
transaction_accounts
.get_mut(0)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::ProgramData {
slot: SLOT,
@ -3008,8 +3083,8 @@ mod tests {
&elf_new,
);
let invalid_upgrade_authority_address = Pubkey::new_unique();
transaction_accounts[6].0 = invalid_upgrade_authority_address;
instruction_accounts[6].pubkey = invalid_upgrade_authority_address;
transaction_accounts.get_mut(6).unwrap().0 = invalid_upgrade_authority_address;
instruction_accounts.get_mut(6).unwrap().pubkey = invalid_upgrade_authority_address;
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3024,7 +3099,7 @@ mod tests {
&elf_orig,
&elf_new,
);
instruction_accounts[6].is_signer = false;
instruction_accounts.get_mut(6).unwrap().is_signer = false;
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3039,7 +3114,11 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[1].1.set_executable(false);
transaction_accounts
.get_mut(1)
.unwrap()
.1
.set_executable(false);
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3054,7 +3133,11 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[1].1.set_owner(Pubkey::new_unique());
transaction_accounts
.get_mut(1)
.unwrap()
.1
.set_owner(Pubkey::new_unique());
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3069,7 +3152,7 @@ mod tests {
&elf_orig,
&elf_new,
);
instruction_accounts[1].is_writable = false;
instruction_accounts.get_mut(1).unwrap().is_writable = false;
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3084,7 +3167,9 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[1]
transaction_accounts
.get_mut(1)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Uninitialized)
.unwrap();
@ -3103,8 +3188,8 @@ mod tests {
&elf_new,
);
let invalid_programdata_address = Pubkey::new_unique();
transaction_accounts[0].0 = invalid_programdata_address;
instruction_accounts[0].pubkey = invalid_programdata_address;
transaction_accounts.get_mut(0).unwrap().0 = invalid_programdata_address;
instruction_accounts.get_mut(0).unwrap().pubkey = invalid_programdata_address;
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3119,7 +3204,9 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[2]
transaction_accounts
.get_mut(2)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Uninitialized)
.unwrap();
@ -3137,12 +3224,14 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[2].1 = AccountSharedData::new(
transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new(
1,
UpgradeableLoaderState::buffer_len(elf_orig.len().max(elf_new.len()) + 1).unwrap(),
&bpf_loader_upgradeable::id(),
);
transaction_accounts[2]
transaction_accounts
.get_mut(2)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: Some(upgrade_authority_address),
@ -3162,13 +3251,15 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[2]
transaction_accounts
.get_mut(2)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: Some(upgrade_authority_address),
})
.unwrap();
truncate_data(&mut transaction_accounts[2].1, 5);
truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
process_instruction(
transaction_accounts,
instruction_accounts,
@ -3197,7 +3288,9 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[2]
transaction_accounts
.get_mut(2)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: None,
@ -3217,14 +3310,18 @@ mod tests {
&elf_orig,
&elf_new,
);
transaction_accounts[0]
transaction_accounts
.get_mut(0)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::ProgramData {
slot: SLOT,
upgrade_authority_address: None,
})
.unwrap();
transaction_accounts[2]
transaction_accounts
.get_mut(2)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: None,
@ -3298,7 +3395,7 @@ mod tests {
],
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::ProgramData {
@ -3319,7 +3416,7 @@ mod tests {
vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::ProgramData {
@ -3462,7 +3559,7 @@ mod tests {
vec![buffer_meta.clone(), authority_meta.clone()],
Err(InstructionError::IncorrectAuthority),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -3488,7 +3585,7 @@ mod tests {
],
Ok(()),
);
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(
state,
UpgradeableLoaderState::Buffer {
@ -3547,7 +3644,9 @@ mod tests {
);
// Case: Set to no authority
transaction_accounts[0]
transaction_accounts
.get_mut(0)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: None,
@ -3567,7 +3666,9 @@ mod tests {
);
// Case: Not a Buffer account
transaction_accounts[0]
transaction_accounts
.get_mut(0)
.unwrap()
.1
.set_state(&UpgradeableLoaderState::Program {
programdata_address: Pubkey::new_unique(),
@ -3670,9 +3771,9 @@ mod tests {
],
Ok(()),
);
assert_eq!(0, accounts[0].lamports());
assert_eq!(2, accounts[1].lamports());
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
assert_eq!(0, accounts.first().unwrap().lamports());
assert_eq!(2, accounts.get(1).unwrap().lamports());
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
// Case: close with wrong authority
@ -3718,9 +3819,9 @@ mod tests {
],
Ok(()),
);
assert_eq!(0, accounts[0].lamports());
assert_eq!(2, accounts[1].lamports());
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
assert_eq!(0, accounts.first().unwrap().lamports());
assert_eq!(2, accounts.get(1).unwrap().lamports());
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
// Case: close a program account
@ -3750,9 +3851,9 @@ mod tests {
],
Ok(()),
);
assert_eq!(0, accounts[0].lamports());
assert_eq!(2, accounts[1].lamports());
let state: UpgradeableLoaderState = accounts[0].state().unwrap();
assert_eq!(0, accounts.first().unwrap().lamports());
assert_eq!(2, accounts.get(1).unwrap().lamports());
let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
assert_eq!(state, UpgradeableLoaderState::Uninitialized);
// Try to invoke closed account
@ -3786,7 +3887,7 @@ mod tests {
for _ in 0..inner_iters {
let offset = rng.gen_range(offset.start, offset.end);
let value = rng.gen_range(value.start, value.end);
mangled_bytes[offset] = value;
*mangled_bytes.get_mut(offset).unwrap() = value;
work(&mut mangled_bytes);
}
}

View File

@ -183,10 +183,18 @@ pub fn deserialize_parameters_unaligned(
start += size_of::<u8>(); // is_signer
start += size_of::<u8>(); // is_writable
start += size_of::<Pubkey>(); // key
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(&buffer[start..]));
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(
buffer
.get(start..)
.ok_or(InstructionError::InvalidArgument)?,
));
start += size_of::<u64>() // lamports
+ size_of::<u64>(); // data length
let _ = borrowed_account.set_data(&buffer[start..start + pre_len]);
let _ = borrowed_account.set_data(
buffer
.get(start..start + pre_len)
.ok_or(InstructionError::InvalidArgument)?,
);
start += pre_len // data
+ size_of::<Pubkey>() // owner
+ size_of::<u8>() // executable
@ -316,11 +324,23 @@ pub fn deserialize_parameters_aligned(
+ size_of::<u8>() // executable
+ 4 // padding to 128-bit aligned
+ size_of::<Pubkey>(); // key
let _ = borrowed_account.set_owner(&buffer[start..start + size_of::<Pubkey>()]);
let _ = borrowed_account.set_owner(
buffer
.get(start..start + size_of::<Pubkey>())
.ok_or(InstructionError::InvalidArgument)?,
);
start += size_of::<Pubkey>(); // owner
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(&buffer[start..]));
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(
buffer
.get(start..)
.ok_or(InstructionError::InvalidArgument)?,
));
start += size_of::<u64>(); // lamports
let post_len = LittleEndian::read_u64(&buffer[start..]) as usize;
let post_len = LittleEndian::read_u64(
buffer
.get(start..)
.ok_or(InstructionError::InvalidArgument)?,
) as usize;
start += size_of::<u64>(); // data length
let data_end = if do_support_realloc {
if post_len.saturating_sub(*pre_len) > MAX_PERMITTED_DATA_INCREASE
@ -338,7 +358,11 @@ pub fn deserialize_parameters_aligned(
}
data_end
};
let _ = borrowed_account.set_data(&buffer[start..data_end]);
let _ = borrowed_account.set_data(
buffer
.get(start..data_end)
.ok_or(InstructionError::InvalidArgument)?,
);
start += *pre_len + MAX_PERMITTED_DATA_INCREASE; // data
start += (start as *const u8).align_offset(BPF_ALIGN_OF_U128);
start += size_of::<u64>(); // rent_epoch
@ -445,7 +469,7 @@ mod tests {
.into_iter()
.enumerate()
.map(|(index_in_instruction, index_in_transaction)| AccountMeta {
pubkey: transaction_accounts[index_in_transaction].0,
pubkey: transaction_accounts.get(index_in_transaction).unwrap().0,
is_signer: false,
is_writable: index_in_instruction >= 4,
})
@ -479,12 +503,12 @@ mod tests {
serialize_parameters(invoke_context.transaction_context, instruction_context).unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize(&mut serialized.as_slice_mut()[0] as *mut u8) };
unsafe { deserialize(serialized.as_slice_mut().first_mut().unwrap() as *mut u8) };
assert_eq!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data);
assert_eq!(
(&de_instruction_data[0] as *const u8).align_offset(BPF_ALIGN_OF_U128),
(de_instruction_data.first().unwrap() as *const u8).align_offset(BPF_ALIGN_OF_U128),
0
);
for account_info in de_accounts {
@ -546,7 +570,9 @@ mod tests {
}
// check serialize_parameters_unaligned
original_accounts[0]
original_accounts
.first_mut()
.unwrap()
.1
.set_owner(bpf_loader_deprecated::id());
let _ = invoke_context
@ -560,8 +586,9 @@ mod tests {
let (mut serialized, account_lengths) =
serialize_parameters(invoke_context.transaction_context, instruction_context).unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize_unaligned(&mut serialized.as_slice_mut()[0] as *mut u8) };
let (de_program_id, de_accounts, de_instruction_data) = unsafe {
deserialize_unaligned(serialized.as_slice_mut().first_mut().unwrap() as *mut u8)
};
assert_eq!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data);
for account_info in de_accounts {
@ -676,7 +703,7 @@ mod tests {
});
} else {
// duplicate account, clone the original
accounts.push(accounts[dup_info as usize].clone());
accounts.push(accounts.get(dup_info as usize).unwrap().clone());
}
}

View File

@ -93,6 +93,8 @@ pub enum SyscallError {
ReturnDataTooLarge(u64, u64),
#[error("Hashing too many sequences")]
TooManySlices,
#[error("InvalidLength")]
InvalidLength,
}
impl From<SyscallError> for EbpfError<BpfError> {
fn from(error: SyscallError) -> Self {
@ -618,9 +620,10 @@ fn translate_string_and_do(
Some(i) => i,
None => len as usize,
};
match from_utf8(&buf[..i]) {
let msg = buf.get(..i).ok_or(SyscallError::InvalidLength)?;
match from_utf8(msg) {
Ok(message) => work(message),
Err(err) => Err(SyscallError::InvalidString(err, buf[..i].to_vec()).into()),
Err(err) => Err(SyscallError::InvalidString(err, msg.to_vec()).into()),
}
}
@ -1555,8 +1558,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcmp<'a, 'b> {
);
let mut i = 0;
while i < n as usize {
let a = s1[i];
let b = s2[i];
let a = *question_mark!(s1.get(i).ok_or(SyscallError::InvalidLength,), result);
let b = *question_mark!(s2.get(i).ok_or(SyscallError::InvalidLength,), result);
if a != b {
*cmp_result = if invoke_context
.feature_set
@ -2406,7 +2409,9 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
loader_id,
)?;
let first_info_addr = &account_infos[0] as *const _ as u64;
let first_info_addr = account_infos.first().ok_or(SyscallError::InstructionError(
InstructionError::InvalidArgument,
))? as *const _ as u64;
let addr = &account_info.data_len as *const u64 as u64;
let vm_addr = if invoke_context
.feature_set
@ -2570,8 +2575,12 @@ where
} else if let Some(caller_account_index) =
account_info_keys.iter().position(|key| *key == account_key)
{
let mut caller_account =
do_translate(&account_infos[caller_account_index], invoke_context)?;
let mut caller_account = do_translate(
account_infos
.get(caller_account_index)
.ok_or(SyscallError::InvalidLength)?,
invoke_context,
)?;
{
let mut account = account.borrow_mut();
account.copy_into_owner_from_slice(caller_account.owner.as_ref());
@ -2585,7 +2594,9 @@ where
.index_in_caller
.saturating_sub(instruction_context.get_number_of_program_accounts());
if orig_data_len_index < orig_data_lens.len() {
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
caller_account.original_data_len = *orig_data_lens
.get(orig_data_len_index)
.ok_or(SyscallError::InvalidLength)?;
} else {
ic_msg!(
invoke_context,
@ -2815,7 +2826,13 @@ fn call<'a, 'b: 'a>(
);
}
if new_len < caller_account.data.len() {
caller_account.data[new_len..].fill(0);
caller_account
.data
.get_mut(new_len..)
.ok_or(SyscallError::InstructionError(
InstructionError::AccountDataTooSmall,
))?
.fill(0);
}
caller_account.data = translate_slice_mut::<u8>(
memory_mapping,
@ -2826,9 +2843,17 @@ fn call<'a, 'b: 'a>(
*caller_account.ref_to_len_in_vm = new_len as u64;
*caller_account.serialized_len_ptr = new_len as u64;
}
caller_account
.data
.copy_from_slice(&callee_account.data()[0..new_len]);
let to_slice = &mut caller_account.data;
let from_slice = callee_account
.data()
.get(0..new_len)
.ok_or(SyscallError::InvalidLength)?;
if to_slice.len() != from_slice.len() {
return Err(
SyscallError::InstructionError(InstructionError::AccountDataTooSmall).into(),
);
}
to_slice.copy_from_slice(from_slice);
}
}
@ -2961,14 +2986,25 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetReturnData<'a, 'b> {
result
);
return_data_result.copy_from_slice(&return_data[..length as usize]);
let to_slice = return_data_result;
let from_slice = question_mark!(
return_data
.get(..length as usize)
.ok_or(SyscallError::InvokeContextBorrowFailed),
result
);
if to_slice.len() != from_slice.len() {
*result = Err(SyscallError::InvalidLength.into());
return;
}
to_slice.copy_from_slice(from_slice);
let program_id_result = question_mark!(
translate_slice_mut::<Pubkey>(memory_mapping, program_id_addr, 1, loader_id),
translate_type_mut::<Pubkey>(memory_mapping, program_id_addr, loader_id),
result
);
program_id_result[0] = *program_id;
*program_id_result = *program_id;
}
// Return the actual length, rather the length returned
@ -3089,7 +3125,7 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetProcessedSiblingInstruction<'
.checked_sub(2)
.and_then(|result| result.checked_sub(index as usize))
.and_then(|index| instruction_trace.get(index))
.and_then(|instruction_list| instruction_list.get(0))
.and_then(|instruction_list| instruction_list.first())
} else {
// Walk the last list of inner instructions
instruction_trace.last().and_then(|inners| {
@ -3419,7 +3455,7 @@ mod tests {
)
.unwrap();
assert_eq!(data, translated_data);
data[0] = 10;
*data.first_mut().unwrap() = 10;
assert_eq!(data, translated_data);
assert!(translate_slice::<u8>(
&memory_mapping,
@ -3462,7 +3498,7 @@ mod tests {
)
.unwrap();
assert_eq!(data, translated_data);
data[0] = 10;
*data.first_mut().unwrap() = 10;
assert_eq!(data, translated_data);
assert!(
translate_slice::<u64>(&memory_mapping, 0x100000000, u64::MAX, &bpf_loader::id())
@ -3494,7 +3530,7 @@ mod tests {
)
.unwrap();
assert_eq!(data, translated_data);
data[0] = solana_sdk::pubkey::new_rand(); // Both should point to same place
*data.first_mut().unwrap() = solana_sdk::pubkey::new_rand(); // Both should point to same place
assert_eq!(data, translated_data);
}
@ -3776,7 +3812,7 @@ mod tests {
};
let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
let addr = &pubkey.as_ref()[0] as *const _ as u64;
let addr = pubkey.as_ref().first().unwrap() as *const _ as u64;
let config = Config::default();
let memory_mapping = MemoryMapping::new::<UserError>(
vec![