Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
eccc3e9
AccountSharedData: make data_mut() private
alessandrod Sep 23, 2022
bd79f9a
Adds the feature bpf_account_data_direct_mapping.
Lichtso Sep 8, 2022
4f8ecd5
Remaps EbpfError::AccessViolation into InstructionError::ReadonlyData…
Lichtso Jul 26, 2022
c494dc3
WIP: Memory regions for each instruction account in create_vm().
Lichtso Sep 7, 2022
0b19f89
Fix serialization benches, run both copy and !copy variants
alessandrod Sep 7, 2022
6ff6d7e
rbpf-cli: fix build
alessandrod Sep 24, 2022
c890819
BorrowedAccount: ensure that account capacity is never reduced
alessandrod Sep 25, 2022
c8b2c2b
bpf_load: run serialization tests for both copy and !copy account data
alessandrod Oct 4, 2022
4df1264
bpf_loader: add Serializer::write_account
alessandrod Oct 4, 2022
e628370
fix lints
alessandrod Oct 4, 2022
7f623b3
BorrowedAccount: make_data_mut is host only
alessandrod Oct 4, 2022
1211f3e
Fix unused import warning
alessandrod Oct 5, 2022
e9daf20
Fix lints
alessandrod Oct 20, 2022
68bde9b
cpi: add explicit direct_mapping arg to update_(callee|caller)_account
alessandrod Oct 27, 2022
17bd0b3
cpi: rename account_data_or_only_realloc_padding to serialized_data
alessandrod Oct 27, 2022
794a0ac
cpi: add CallerAccount::original_data_len comment
alessandrod Oct 27, 2022
5081d99
cpi: add update_callee_account direct_mapping test
alessandrod Oct 27, 2022
2d946d4
cpi: add test_update_caller_account_data_direct_mapping and fix bug
alessandrod Oct 28, 2022
2b76f82
cpi: add tests for mutated readonly accounts
alessandrod Oct 29, 2022
79fea1a
cpi: update_caller_account doesn't need to change .serialized_data wh…
alessandrod Oct 29, 2022
b218e82
cpi: update_caller_account: ensure that account capacity is always en…
alessandrod Oct 29, 2022
0f8aee0
cpi: zero account capacity using the newly introduced BorrowedAccount…
alessandrod Nov 11, 2022
7cb46e9
bpf_loader: fix same lint for the umpteenth time
alessandrod Nov 12, 2022
ee7b971
bpf_loader: map AccessViolation to ReadonlyDataModified only for acco…
alessandrod Dec 15, 2022
460e185
programs/sbf: realloc: add test for large write after realloc
alessandrod Dec 19, 2022
12e18b6
programs/sbf: run test_program_sbf_realloc with both direct_mapping o…
alessandrod Dec 21, 2022
91a6db8
bpf_loader: tweak memcmp syscall
alessandrod Dec 22, 2022
3c756c1
bpf_loader: tweak the memset syscall
alessandrod Dec 22, 2022
c4ca5ad
bpf_loader: syscalls: update mem syscalls to work with non contiguous…
alessandrod Jan 8, 2023
f8040ec
fix lint, rebase mem_ops
alessandrod Jan 9, 2023
5ade076
Implement CoW for writable accounts
alessandrod Feb 13, 2023
327005e
Fix CI
alessandrod Feb 14, 2023
292f7f0
Move CoW to the MemoryMapping level
alessandrod Feb 22, 2023
f5bd31b
Update after rbpf API change
alessandrod Feb 27, 2023
b00ae65
Fix merge screwup
alessandrod Feb 27, 2023
fbe4d84
Add create_vm macro. Fix benches.
alessandrod Feb 27, 2023
0645120
cpi: simplify update_caller_account
alessandrod Feb 28, 2023
533f96d
benches/bpf_loader: move serialization out of create_vm bench
alessandrod Mar 1, 2023
9b62770
benches/bpf_loader: don't copy accounts when direct mapping is on
alessandrod Mar 2, 2023
db53617
Fix review nits
alessandrod Mar 15, 2023
09c7154
bpf_loader: mem_ops: handle u64 overflow in MemoryChunkIterator::new
alessandrod Apr 17, 2023
1e18a73
Fix loader-v3 tests: data_mut => data_as_mut_slice
alessandrod Apr 18, 2023
490ccd0
Fix CI
alessandrod Apr 18, 2023
9b4cbb3
bpf_loader: fix tuner bench: account must be writable
alessandrod Apr 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ pub fn builtin_process_instruction(
invoke_context
.transaction_context
.get_current_instruction_context()?,
true,
true, // should_cap_ix_accounts
true, // copy_account_data // There is no VM so direct mapping can not be implemented here
)?;

// Deserialize data back into instruction params
Expand Down
37 changes: 33 additions & 4 deletions programs/bpf_loader/benches/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,20 @@ fn bench_serialize_unaligned(bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ =
serialize_parameters(&transaction_context, instruction_context, true, false).unwrap();
});
}

#[bench]
fn bench_serialize_unaligned_copy_account_data(bencher: &mut Bencher) {
let transaction_context = create_inputs(bpf_loader_deprecated::id(), 7);
let instruction_context = transaction_context
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ =
serialize_parameters(&transaction_context, instruction_context, true, true).unwrap();
});
}

Expand All @@ -138,7 +151,21 @@ fn bench_serialize_aligned(bencher: &mut Bencher) {
.unwrap();

bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ =
serialize_parameters(&transaction_context, instruction_context, true, false).unwrap();
});
}

#[bench]
fn bench_serialize_aligned_copy_account_data(bencher: &mut Bencher) {
let transaction_context = create_inputs(bpf_loader::id(), 7);
let instruction_context = transaction_context
.get_current_instruction_context()
.unwrap();

bencher.iter(|| {
let _ =
serialize_parameters(&transaction_context, instruction_context, true, true).unwrap();
});
}

Expand All @@ -149,7 +176,8 @@ fn bench_serialize_unaligned_max_accounts(bencher: &mut Bencher) {
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ =
serialize_parameters(&transaction_context, instruction_context, true, false).unwrap();
});
}

Expand All @@ -161,6 +189,7 @@ fn bench_serialize_aligned_max_accounts(bencher: &mut Bencher) {
.unwrap();

bencher.iter(|| {
let _ = serialize_parameters(&transaction_context, instruction_context, true).unwrap();
let _ =
serialize_parameters(&transaction_context, instruction_context, true, false).unwrap();
});
}
86 changes: 74 additions & 12 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,24 @@ use {
aligned_memory::AlignedMemory,
ebpf::{self, HOST_ALIGN, MM_HEAP_START},
elf::Executable,
memory_region::{MemoryCowCallback, MemoryMapping, MemoryRegion},
error::EbpfError,
memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
verifier::RequisiteVerifier,
vm::{ContextObject, EbpfVm, ProgramResult, VerifiedExecutable},
},
solana_sdk::{
account::WritableAccount,
bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Slot,
entrypoint::SUCCESS,
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{
cap_accounts_data_allocations_per_transaction, cap_bpf_program_instruction_accounts,
delay_visibility_of_program_deployment, disable_deploy_of_alloc_free_syscall,
enable_bpf_loader_extend_program_ix, enable_bpf_loader_set_authority_checked_ix,
enable_program_redeployment_cooldown, limit_max_instruction_trace_length,
native_programs_consume_cu, remove_bpf_loader_incorrect_program_id, FeatureSet,
bpf_account_data_direct_mapping, cap_accounts_data_allocations_per_transaction,
cap_bpf_program_instruction_accounts, delay_visibility_of_program_deployment,
disable_deploy_of_alloc_free_syscall, enable_bpf_loader_extend_program_ix,
enable_bpf_loader_set_authority_checked_ix, enable_program_redeployment_cooldown,
limit_max_instruction_trace_length, native_programs_consume_cu,
remove_bpf_loader_incorrect_program_id, FeatureSet,
},
instruction::{AccountMeta, InstructionError},
loader_instruction::LoaderInstruction,
Expand Down Expand Up @@ -302,8 +305,31 @@ pub fn create_vm<'a, 'b>(
) -> Result<EbpfVm<'a, RequisiteVerifier, InvokeContext<'b>>, Box<dyn std::error::Error>> {
let stack_size = stack.len();
let heap_size = heap.len();
let memory_mapping =
create_memory_mapping(program.get_executable(), stack, heap, regions, None)?;
let accounts = Arc::clone(invoke_context.transaction_context.accounts());
let memory_mapping = create_memory_mapping(
program.get_executable(),
stack,
heap,
regions,
Some(Box::new(move |index_in_transaction| {
// The two calls below can't really fail. If they fail because of a bug,
// whatever is writing will trigger an EbpfError::AccessViolation like
// if the region was readonly, and the transaction will fail gracefully.
let mut account = accounts
.try_borrow_mut(index_in_transaction as IndexOfAccount)
.map_err(|_| ())?;
accounts
.touch(index_in_transaction as IndexOfAccount)
.map_err(|_| ())?;

if account.is_shared() {
// See BorrowedAccount::make_data_mut() as to why we reserve extra
// MAX_PERMITTED_DATA_INCREASE bytes here.
account.reserve(MAX_PERMITTED_DATA_INCREASE);
}
Ok(account.data_as_mut_slice().as_mut_ptr() as u64)
})),
)?;
invoke_context.set_syscall_context(SyscallContext {
allocator: BpfAllocator::new(heap_size as u64),
orig_account_lengths,
Expand Down Expand Up @@ -1524,6 +1550,9 @@ fn execute<'a, 'b: 'a>(
let use_jit = false;
#[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
let use_jit = executable.get_executable().get_compiled_program().is_some();
let bpf_account_data_direct_mapping = invoke_context
.feature_set
.is_active(&bpf_account_data_direct_mapping::id());

let mut serialize_time = Measure::start("serialize");
let (parameter_bytes, regions, account_lengths) = serialization::serialize_parameters(
Expand All @@ -1532,9 +1561,19 @@ fn execute<'a, 'b: 'a>(
invoke_context
.feature_set
.is_active(&cap_bpf_program_instruction_accounts::ID),
!bpf_account_data_direct_mapping,
)?;
serialize_time.stop();

// save the account addresses so in case of AccessViolation below we can
// map to InstructionError::ReadonlyDataModified, which is easier to
// diagnose from developers
let account_region_addrs = regions
.iter()
.map(|r| r.vm_addr..r.vm_addr.saturating_add(r.len))
.collect::<Vec<_>>();
let addr_is_account_data = |addr: u64| account_region_addrs.iter().any(|r| r.contains(&addr));

let mut create_vm_time = Measure::start("create_vm");
let mut execute_time;
let execution_result = {
Expand Down Expand Up @@ -1597,7 +1636,24 @@ fn execute<'a, 'b: 'a>(
};
Err(Box::new(error) as Box<dyn std::error::Error>)
}
ProgramResult::Err(error) => Err(error),
ProgramResult::Err(error) => {
let error = match error.downcast_ref() {
Some(EbpfError::AccessViolation(
_pc,
AccessType::Store,
address,
_size,
_section_name,
)) if addr_is_account_data(*address) => {
// We can get here if direct_mapping is enabled and a program tries to
// write to a readonly account. Map the error to ReadonlyDataModified so
// it's easier for devs to diagnose what happened.
Box::new(InstructionError::ReadonlyDataModified)
}
_ => error,
};
Err(error)
}
_ => Ok(()),
}
};
Expand All @@ -1606,21 +1662,27 @@ fn execute<'a, 'b: 'a>(
fn deserialize_parameters(
invoke_context: &mut InvokeContext,
parameter_bytes: &[u8],
copy_account_data: bool,
) -> Result<(), InstructionError> {
serialization::deserialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()?,
copy_account_data,
parameter_bytes,
&invoke_context.get_syscall_context()?.orig_account_lengths,
)
}

let mut deserialize_time = Measure::start("deserialize");
let execute_or_deserialize_result = execution_result.and_then(|_| {
deserialize_parameters(invoke_context, parameter_bytes.as_slice())
.map_err(|error| Box::new(error) as Box<dyn std::error::Error>)
deserialize_parameters(
invoke_context,
parameter_bytes.as_slice(),
!bpf_account_data_direct_mapping,
)
.map_err(|error| Box::new(error) as Box<dyn std::error::Error>)
});
deserialize_time.stop();

Expand Down
Loading