Enforce host aligned memory for program regions (backport #16590) (#16683)

* Enforce host aligned memory for program regions (#16590)

(cherry picked from commit 08d5253651)

# Conflicts:
#	cli/Cargo.toml
#	programs/bpf/Cargo.toml
#	programs/bpf/benches/bpf_loader.rs
#	programs/bpf/tests/programs.rs
#	programs/bpf_loader/Cargo.toml
#	programs/bpf_loader/src/lib.rs

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
mergify[bot]
2021-04-21 01:47:00 +00:00
committed by GitHub
parent a5794efe16
commit bbd8bd2e74
12 changed files with 399 additions and 127 deletions

View File

@@ -20,7 +20,7 @@ rand_core = "0.6.2"
solana-measure = { path = "../../measure", version = "=1.6.7" }
solana-runtime = { path = "../../runtime", version = "=1.6.7" }
solana-sdk = { path = "../../sdk", version = "=1.6.7" }
solana_rbpf = "=0.2.7"
solana_rbpf = "=0.2.8"
thiserror = "1.0"
[dev-dependencies]

View File

@@ -1,18 +1,19 @@
use crate::alloc;
use alloc::{Alloc, AllocErr};
use solana_rbpf::aligned_memory::AlignedMemory;
use std::alloc::Layout;
#[derive(Debug)]
pub struct BpfAllocator {
heap: Vec<u8>,
heap: AlignedMemory,
start: u64,
len: u64,
pos: u64,
}
impl BpfAllocator {
pub fn new(heap: Vec<u8>, virtual_address: u64) -> Self {
pub fn new(heap: AlignedMemory, virtual_address: u64) -> Self {
let len = heap.len() as u64;
Self {
heap,

View File

@@ -17,7 +17,8 @@ use crate::{
use log::{log_enabled, trace, Level::Trace};
use solana_measure::measure::Measure;
use solana_rbpf::{
ebpf::MM_HEAP_START,
aligned_memory::AlignedMemory,
ebpf::{HOST_ALIGN, MM_HEAP_START},
error::{EbpfError, UserDefinedError},
memory_region::MemoryRegion,
vm::{Config, EbpfVm, Executable, InstructionMeter},
@@ -146,8 +147,8 @@ pub fn create_vm<'a>(
parameter_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext,
) -> Result<EbpfVm<'a, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> {
let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START, 0, true);
let heap = AlignedMemory::new(DEFAULT_HEAP_SIZE, HOST_ALIGN);
let heap_region = MemoryRegion::new_from_slice(heap.as_slice(), MM_HEAP_START, 0, true);
let mut vm = EbpfVm::new(program, parameter_bytes, &[heap_region])?;
syscalls::bind_syscall_context_objects(
loader_id,
@@ -793,7 +794,7 @@ impl Executor for BpfExecutor {
let mut vm = match create_vm(
loader_id,
self.program.as_ref(),
&mut parameter_bytes,
parameter_bytes.as_slice_mut(),
&parameter_accounts,
invoke_context,
) {
@@ -857,7 +858,7 @@ impl Executor for BpfExecutor {
deserialize_parameters(
loader_id,
parameter_accounts,
&parameter_bytes,
parameter_bytes.as_slice(),
invoke_context.is_feature_active(&skip_ro_deserialization::id()),
)?;
deserialize_time.stop();

View File

@@ -1,4 +1,5 @@
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use solana_rbpf::{aligned_memory::AlignedMemory, ebpf::HOST_ALIGN};
use solana_sdk::{
account::{ReadableAccount, WritableAccount},
bpf_loader_deprecated,
@@ -27,7 +28,7 @@ pub fn serialize_parameters(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
) -> Result<Vec<u8>, InstructionError> {
) -> Result<AlignedMemory, InstructionError> {
if *loader_id == bpf_loader_deprecated::id() {
serialize_parameters_unaligned(program_id, keyed_accounts, data)
} else {
@@ -69,7 +70,7 @@ pub fn serialize_parameters_unaligned(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
) -> Result<Vec<u8>, InstructionError> {
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
@@ -82,7 +83,7 @@ pub fn serialize_parameters_unaligned(
size += size_of::<u64>() // instruction data len
+ instruction_data.len() // instruction data
+ size_of::<Pubkey>(); // program id
let mut v: Vec<u8> = Vec::with_capacity(size);
let mut v = AlignedMemory::new(size, HOST_ALIGN);
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
@@ -182,7 +183,7 @@ pub fn serialize_parameters_aligned(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
) -> Result<Vec<u8>, InstructionError> {
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
@@ -197,14 +198,11 @@ pub fn serialize_parameters_aligned(
size += size_of::<u64>() // data len
+ instruction_data.len()
+ size_of::<Pubkey>(); // program id;
let mut v: Vec<u8> = Vec::with_capacity(size);
let mut v = AlignedMemory::new(size, HOST_ALIGN);
// Serialize into the buffer
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
if v.as_ptr().align_offset(align_of::<u128>()) != 0 {
panic!();
}
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account);
if is_dup {
@@ -233,12 +231,12 @@ pub fn serialize_parameters_aligned(
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(&keyed_account.try_account_ref()?.data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.resize(
v.len()
+ MAX_PERMITTED_DATA_INCREASE
+ (v.len() as *const u8).align_offset(align_of::<u128>()),
v.fill(
MAX_PERMITTED_DATA_INCREASE
+ (v.write_index() as *const u8).align_offset(align_of::<u128>()),
0,
);
)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
}
@@ -414,7 +412,8 @@ mod tests {
.unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize(&mut serialized[0] as *mut u8) };
unsafe { deserialize(&mut serialized.as_slice_mut()[0] as *mut u8) };
assert_eq!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data);
assert_eq!(
@@ -457,7 +456,13 @@ mod tests {
}
})
.collect();
deserialize_parameters(&bpf_loader::id(), &de_keyed_accounts, &serialized, true).unwrap();
deserialize_parameters(
&bpf_loader::id(),
&de_keyed_accounts,
serialized.as_slice(),
true,
)
.unwrap();
for ((account, de_keyed_account), key) in
accounts.iter().zip(de_keyed_accounts).zip(keys.clone())
{
@@ -484,7 +489,7 @@ mod tests {
.unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize_unaligned(&mut serialized[0] as *mut u8) };
unsafe { deserialize_unaligned(&mut serialized.as_slice_mut()[0] as *mut u8) };
assert_eq!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data);
for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys.clone()) {
@@ -513,7 +518,7 @@ mod tests {
deserialize_parameters(
&bpf_loader_deprecated::id(),
&de_keyed_accounts,
&serialized,
serialized.as_slice(),
true,
)
.unwrap();

File diff suppressed because it is too large Load Diff