Limit CPI instruction size (#14317)
This commit is contained in:
@@ -1018,6 +1018,7 @@ mod tests {
|
||||
max_call_depth: 20,
|
||||
stack_frame_size: 4096,
|
||||
log_pubkey_units: 100,
|
||||
max_cpi_instruction_size: usize::MAX,
|
||||
},
|
||||
Rc::new(RefCell::new(Executors::default())),
|
||||
None,
|
||||
|
@@ -845,6 +845,7 @@ trait SyscallInvokeSigned<'a> {
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
max_size: usize,
|
||||
memory_mapping: &MemoryMapping,
|
||||
) -> Result<Instruction, EbpfError<BPFError>>;
|
||||
fn translate_accounts(
|
||||
@@ -882,9 +883,12 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
max_size: usize,
|
||||
memory_mapping: &MemoryMapping,
|
||||
) -> Result<Instruction, EbpfError<BPFError>> {
|
||||
let ix = translate_type::<Instruction>(memory_mapping, addr, self.loader_id)?;
|
||||
check_instruction_size(ix.accounts.len(), ix.data.len(), max_size)?;
|
||||
|
||||
let accounts = translate_slice::<AccountMeta>(
|
||||
memory_mapping,
|
||||
ix.accounts.as_ptr() as u64,
|
||||
@@ -1144,15 +1148,19 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
||||
}
|
||||
|
||||
fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>] {
|
||||
self.callers_keyed_accounts
|
||||
}
|
||||
|
||||
fn translate_instruction(
|
||||
&self,
|
||||
addr: u64,
|
||||
max_size: usize,
|
||||
memory_mapping: &MemoryMapping,
|
||||
) -> Result<Instruction, EbpfError<BPFError>> {
|
||||
let ix_c = translate_type::<SolInstruction>(memory_mapping, addr, self.loader_id)?;
|
||||
check_instruction_size(ix_c.accounts_len, ix_c.data_len, max_size)?;
|
||||
let program_id =
|
||||
translate_type::<Pubkey>(memory_mapping, ix_c.program_id_addr, self.loader_id)?;
|
||||
let meta_cs = translate_slice::<SolAccountMeta>(
|
||||
@@ -1352,7 +1360,20 @@ impl<'a> SyscallObject<BPFError> for SyscallInvokeSignedC<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_authorized_program(program_id: &Pubkey) -> Result<(), EbpfError<BPFError>> {
|
||||
fn check_instruction_size(
|
||||
num_accounts: usize,
|
||||
data_len: usize,
|
||||
max_size: usize,
|
||||
) -> Result<(), EbpfError<BPFError>> {
|
||||
if max_size < num_accounts * size_of::<AccountMeta>() + data_len {
|
||||
return Err(
|
||||
SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded).into(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_authorized_program(program_id: &Pubkey) -> Result<(), EbpfError<BPFError>> {
|
||||
if native_loader::check_id(program_id)
|
||||
|| bpf_loader::check_id(program_id)
|
||||
|| bpf_loader_deprecated::check_id(program_id)
|
||||
@@ -1380,7 +1401,13 @@ fn call<'a>(
|
||||
|
||||
// Translate and verify caller's data
|
||||
|
||||
let instruction = syscall.translate_instruction(instruction_addr, &memory_mapping)?;
|
||||
let instruction = syscall.translate_instruction(
|
||||
instruction_addr,
|
||||
invoke_context
|
||||
.get_bpf_compute_budget()
|
||||
.max_cpi_instruction_size,
|
||||
&memory_mapping,
|
||||
)?;
|
||||
let caller_program_id = invoke_context
|
||||
.get_caller()
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
@@ -1397,7 +1424,7 @@ fn call<'a>(
|
||||
let (message, callee_program_id, program_id_index) =
|
||||
MessageProcessor::create_message(&instruction, &keyed_account_refs, &signers)
|
||||
.map_err(SyscallError::InstructionError)?;
|
||||
is_authorized_program(&callee_program_id)?;
|
||||
check_authorized_program(&callee_program_id)?;
|
||||
let (mut accounts, mut account_refs) = syscall.translate_accounts(
|
||||
&message.account_keys,
|
||||
program_id_index,
|
||||
|
Reference in New Issue
Block a user