Skip to content

Commit

Permalink
v2.1: Check account boundaries on overlapping memmove syscall (backpo…
Browse files Browse the repository at this point in the history
…rt of solana-labs#4563) (solana-labs#4598)

Check account boundaries on overlapping memmove syscall (solana-labs#4563)

* fix reverse memmove

(cherry picked from commit 4b89b0f)

Co-authored-by: Sean Young <[email protected]>
  • Loading branch information
mergify[bot] and seanyoung authored Jan 26, 2025
1 parent 134be7c commit 8ff524b
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 7 deletions.
47 changes: 43 additions & 4 deletions programs/bpf_loader/src/syscalls/mem_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ struct MemoryChunkIterator<'a> {
// exclusive end index (start + len, so one past the last valid address)
vm_addr_end: u64,
len: u64,
account_index: usize,
account_index: Option<usize>,
is_account: Option<bool>,
}

Expand All @@ -446,7 +446,7 @@ impl<'a> MemoryChunkIterator<'a> {
len,
vm_addr_start: vm_addr,
vm_addr_end,
account_index: 0,
account_index: None,
is_account: None,
})
}
Expand Down Expand Up @@ -490,14 +490,18 @@ impl<'a> Iterator for MemoryChunkIterator<'a> {

let region_is_account;

let mut account_index = self.account_index.unwrap_or_default();
self.account_index = Some(account_index);

loop {
if let Some(account) = self.accounts.get(self.account_index) {
if let Some(account) = self.accounts.get(account_index) {
let account_addr = account.vm_data_addr;
let resize_addr = account_addr.saturating_add(account.original_data_len as u64);

if resize_addr < region.vm_addr {
// region is after this account, move on next one
self.account_index = self.account_index.saturating_add(1);
account_index = account_index.saturating_add(1);
self.account_index = Some(account_index);
} else {
region_is_account =
region.vm_addr == account_addr || region.vm_addr == resize_addr;
Expand Down Expand Up @@ -550,6 +554,41 @@ impl<'a> DoubleEndedIterator for MemoryChunkIterator<'a> {
}
};

let region_is_account;

let mut account_index = self
.account_index
.unwrap_or_else(|| self.accounts.len().saturating_sub(1));
self.account_index = Some(account_index);

loop {
let Some(account) = self.accounts.get(account_index) else {
// address is after all the accounts
region_is_account = false;
break;
};

let account_addr = account.vm_data_addr;
let resize_addr = account_addr.saturating_add(account.original_data_len as u64);

if account_index > 0 && account_addr > region.vm_addr {
account_index = account_index.saturating_sub(1);

self.account_index = Some(account_index);
} else {
region_is_account = region.vm_addr == account_addr || region.vm_addr == resize_addr;
break;
}
}

if let Some(is_account) = self.is_account {
if is_account != region_is_account {
return Some(Err(SyscallError::InvalidLength.into()));
}
} else {
self.is_account = Some(region_is_account);
}

let chunk_len = if region.vm_addr >= self.vm_addr_start {
// consume the whole region
let len = self.vm_addr_end.saturating_sub(region.vm_addr);
Expand Down
15 changes: 14 additions & 1 deletion programs/sbf/rust/account_mem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,20 @@ pub fn process_instruction(
// memmov dst overlaps begin of account
unsafe { sol_memmove(too_early(3).as_mut_ptr(), buf.as_ptr(), 10) };
}

14 => {
// memmove dst overlaps begin of account, reverse order
unsafe { sol_memmove(too_early(0).as_mut_ptr(), too_early(3).as_ptr(), 10) };
}
15 => {
// memmove dst overlaps end of account, reverse order
unsafe {
sol_memmove(
data[data_len..].as_mut_ptr(),
data[data_len.saturating_sub(3)..].as_mut_ptr(),
10,
)
};
}
_ => {}
}

Expand Down
2 changes: 1 addition & 1 deletion programs/sbf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5646,7 +5646,7 @@ fn test_mem_syscalls_overlap_account_begin_or_end() {
let account = AccountSharedData::new(42, 1024, &program_id);
bank.store_account(&account_keypair.pubkey(), &account);

for instr in 0..=13 {
for instr in 0..=15 {
println!("Testing direct_mapping:{direct_mapping} instruction:{instr}");
let instruction =
Instruction::new_with_bytes(program_id, &[instr], account_metas.clone());
Expand Down
2 changes: 1 addition & 1 deletion sdk/feature-set/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ pub mod apply_cost_tracker_during_replay {
solana_pubkey::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj");
}
pub mod bpf_account_data_direct_mapping {
solana_pubkey::declare_id!("GJVDwRkUPNdk9QaK4VsU4g1N41QNxhy1hevjf8kz45Mq");
solana_pubkey::declare_id!("FNPWmNbHbYy1R8JWVZgCPqsoRBcRu4F6ezSnq5o97Px");
}

pub mod add_set_tx_loaded_accounts_data_size_instruction {
Expand Down

0 comments on commit 8ff524b

Please sign in to comment.