Prevent the invoke and upgrade of programs in the same tx batch (#14653)

* Prevent the invoke and upgrade of programs in the same tx batch

* Pass program address as writable in the upgrade instruction
This commit is contained in:
Jack May
2021-01-19 16:24:44 -08:00
committed by GitHub
parent 4964b0fe61
commit e3bd9e5300
9 changed files with 1544 additions and 162 deletions

View File

@ -26,7 +26,7 @@ use solana_sdk::{
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Clock,
entrypoint::SUCCESS,
feature_set::bpf_compute_budget_balancing,
feature_set::{bpf_compute_budget_balancing, prevent_upgrade_and_invoke},
instruction::InstructionError,
keyed_account::{from_keyed_account, next_keyed_account, KeyedAccount},
loader_instruction::LoaderInstruction,
@ -470,6 +470,12 @@ fn process_loader_upgradeable_instruction(
log!(logger, "Program account not executable");
return Err(InstructionError::AccountNotExecutable);
}
if !program.is_writable()
&& invoke_context.is_feature_active(&prevent_upgrade_and_invoke::id())
{
log!(logger, "Program account not writeable");
return Err(InstructionError::InvalidArgument);
}
if &program.owner()? != program_id {
log!(logger, "Program account not owned by loader");
return Err(InstructionError::IncorrectProgramId);
@ -2000,7 +2006,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2062,7 +2068,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2095,7 +2101,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2128,7 +2134,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2162,7 +2168,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2192,6 +2198,39 @@ mod tests {
program_account.borrow_mut().owner = Pubkey::new_unique();
assert_eq!(
Err(InstructionError::IncorrectProgramId),
process_instruction(
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
KeyedAccount::new_readonly(&sysvar::clock::id(), false, &clock_account),
KeyedAccount::new_readonly(
&upgrade_authority_address,
true,
&upgrade_authority_account
)
],
&instruction,
&mut MockInvokeContext::default()
)
);
// Case: Program account not writable
let (buffer_account, program_account, programdata_account, spill_account) = get_accounts(
&buffer_address,
&programdata_address,
&upgrade_authority_address,
slot,
&elf_orig,
&elf_new,
min_program_balance,
min_programdata_balance,
);
assert_eq!(
Err(InstructionError::InvalidArgument),
process_instruction(
&bpf_loader_upgradeable::id(),
&[
@ -2233,7 +2272,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2270,7 +2309,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2303,7 +2342,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&Pubkey::new_unique(), false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2340,7 +2379,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2384,7 +2423,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
@ -2419,7 +2458,7 @@ mod tests {
&bpf_loader_upgradeable::id(),
&[
KeyedAccount::new(&programdata_address, false, &programdata_account),
KeyedAccount::new_readonly(&program_address, false, &program_account),
KeyedAccount::new(&program_address, false, &program_account),
KeyedAccount::new(&buffer_address, false, &buffer_account),
KeyedAccount::new(&spill_address, false, &spill_account),
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),