Skip to content

Commit

Permalink
If the account length is zero, no data region is present (#5122)
Browse files Browse the repository at this point in the history
This only affects unaligned programs, as for aligned programs the resize
area address will match the account region address if the data length is
zero.
  • Loading branch information
seanyoung authored Mar 4, 2025
1 parent 18b49da commit 561023d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 5 deletions.
4 changes: 2 additions & 2 deletions programs/bpf_loader/src/syscalls/mem_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ impl<'a> Iterator for MemoryChunkIterator<'a> {
account_index = account_index.saturating_add(1);
self.account_index = Some(account_index);
} else {
region_is_account = region.vm_addr == account_addr
region_is_account = (account.original_data_len != 0 && region.vm_addr == account_addr)
// unaligned programs do not have a resize area
|| (self.resize_area && region.vm_addr == resize_addr);
break;
Expand Down Expand Up @@ -604,7 +604,7 @@ impl DoubleEndedIterator for MemoryChunkIterator<'_> {

self.account_index = Some(account_index);
} else {
region_is_account = region.vm_addr == account_addr
region_is_account = (account.original_data_len != 0 && region.vm_addr == account_addr)
// unaligned programs do not have a resize area
|| (self.resize_area && region.vm_addr == resize_addr);
break;
Expand Down
7 changes: 7 additions & 0 deletions programs/sbf/rust/account_mem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ pub fn process_instruction(
sol_memset(&mut data[data_len.saturating_sub(2)..], 0, 3);
}
5 => {
// memcmp overlaps begining
#[allow(clippy::manual_memcpy)]
for i in 0..3 {
buf[i] = too_early(2)[i];
}

// memset overlaps begin of account area
sol_memset(too_early(2), 3, 3);
sol_memcpy(too_early(2), &buf, 3);
}
6 => {
// memcpy src overlaps end of account
Expand Down
6 changes: 3 additions & 3 deletions programs/sbf/rust/account_mem_deprecated/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn process_instruction(
let mut too_early = |before: usize| -> &mut [u8] {
let data = data.as_mut_ptr().wrapping_sub(before);

unsafe { std::slice::from_raw_parts_mut(data, data_len) }
unsafe { std::slice::from_raw_parts_mut(data, data_len.wrapping_add(100)) }
};

match instruction_data[0] {
Expand All @@ -40,11 +40,11 @@ pub fn process_instruction(
2 => {
// memcmp overlaps begining
#[allow(clippy::manual_memcpy)]
for i in 0..500 {
for i in 0..90 {
buf[i] = too_early(8)[i];
}

sol_memcmp(too_early(8), &buf, 500);
sol_memcmp(too_early(8), &buf, 90);
}
3 => {
// memcmp overlaps begining
Expand Down
23 changes: 23 additions & 0 deletions programs/sbf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5194,6 +5194,29 @@ fn test_mem_syscalls_overlap_account_begin_or_end() {
assert!(!logs.last().unwrap().ends_with(" failed: InvalidLength"));
}
}

let account = AccountSharedData::new(42, 0, &program_id);
bank.store_account(&account_keypair.pubkey(), &account);

for instr in 0..=15 {
println!("Testing deprecated:{deprecated} direct_mapping:{direct_mapping} instruction:{instr} zero-length account");
let instruction =
Instruction::new_with_bytes(program_id, &[instr, 0], account_metas.clone());

let message = Message::new(&[instruction], Some(&mint_pubkey));
let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);

if direct_mapping && !deprecated {
// we have a resize area
assert!(
logs.last().unwrap().ends_with(" failed: InvalidLength"),
"{logs:?}"
);
} else {
assert!(result.is_ok(), "{logs:?}");
}
}
}
}
}

0 comments on commit 561023d

Please sign in to comment.