Fix CPI duplicate account privilege escalation (#22752)

* Adds TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER and TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE.

* Moves CPI privilege verification out of deduplication loop.
This commit is contained in:
Alexander Meißner
2022-01-28 00:52:02 +01:00
committed by GitHub
parent fa51e5b704
commit a71f05f86c
5 changed files with 115 additions and 28 deletions

View File

@@ -698,33 +698,6 @@ impl<'a> InvokeContext<'a> {
);
InstructionError::MissingAccount
})?;
let borrowed_account = instruction_context
.try_borrow_account(self.transaction_context, index_in_caller)?;
// Readonly in caller cannot become writable in callee
if account_meta.is_writable && !borrowed_account.is_writable() {
ic_msg!(
self,
"{}'s writable privilege escalated",
borrowed_account.get_key(),
);
return Err(InstructionError::PrivilegeEscalation);
}
// To be signed in the callee,
// it must be either signed in the caller or by the program
if account_meta.is_signer
&& !(borrowed_account.is_signer()
|| signers.contains(borrowed_account.get_key()))
{
ic_msg!(
self,
"{}'s signer privilege escalated",
borrowed_account.get_key()
);
return Err(InstructionError::PrivilegeEscalation);
}
duplicate_indicies.push(deduplicated_instruction_accounts.len());
deduplicated_instruction_accounts.push(InstructionAccount {
index_in_transaction,
@@ -734,6 +707,35 @@ impl<'a> InvokeContext<'a> {
});
}
}
for instruction_account in deduplicated_instruction_accounts.iter() {
let borrowed_account = instruction_context.try_borrow_account(
self.transaction_context,
instruction_account.index_in_caller,
)?;
// Readonly in caller cannot become writable in callee
if instruction_account.is_writable && !borrowed_account.is_writable() {
ic_msg!(
self,
"{}'s writable privilege escalated",
borrowed_account.get_key(),
);
return Err(InstructionError::PrivilegeEscalation);
}
// To be signed in the callee,
// it must be either signed in the caller or by the program
if instruction_account.is_signer
&& !(borrowed_account.is_signer() || signers.contains(borrowed_account.get_key()))
{
ic_msg!(
self,
"{}'s signer privilege escalated",
borrowed_account.get_key()
);
return Err(InstructionError::PrivilegeEscalation);
}
}
let instruction_accounts: Vec<InstructionAccount> = duplicate_indicies
.into_iter()
.map(|duplicate_index| deduplicated_instruction_accounts[duplicate_index].clone())