Enforce host aligned memory for program regions (#16590)

This commit is contained in:
Jack May 2021-04-20 11:07:30 -07:00 committed by GitHub
parent 8e69dd42c1
commit 08d5253651
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 399 additions and 127 deletions

4
Cargo.lock generated
View File

@ -5471,9 +5471,9 @@ dependencies = [
[[package]] [[package]]
name = "solana_rbpf" name = "solana_rbpf"
version = "0.2.7" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14e36c51d5aa290416c5dea3c43ac467cb57c0b643184af23e6bdab7434710fb" checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"combine", "combine",

View File

@ -38,7 +38,7 @@ solana-config-program = { path = "../programs/config", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" } solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" } solana-logger = { path = "../logger", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" } solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana_rbpf = "=0.2.7" solana_rbpf = "=0.2.8"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" } solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" } solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" } solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }

View File

@ -3595,9 +3595,9 @@ dependencies = [
[[package]] [[package]]
name = "solana_rbpf" name = "solana_rbpf"
version = "0.2.7" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14e36c51d5aa290416c5dea3c43ac467cb57c0b643184af23e6bdab7434710fb" checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
dependencies = [ dependencies = [
"byteorder 1.3.4", "byteorder 1.3.4",
"combine", "combine",

View File

@ -29,7 +29,7 @@ solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.7.0" }
solana-cli-output = { path = "../../cli-output", version = "=1.7.0" } solana-cli-output = { path = "../../cli-output", version = "=1.7.0" }
solana-logger = { path = "../../logger", version = "=1.7.0" } solana-logger = { path = "../../logger", version = "=1.7.0" }
solana-measure = { path = "../../measure", version = "=1.7.0" } solana-measure = { path = "../../measure", version = "=1.7.0" }
solana_rbpf = "=0.2.7" solana_rbpf = "=0.2.8"
solana-runtime = { path = "../../runtime", version = "=1.7.0" } solana-runtime = { path = "../../runtime", version = "=1.7.0" }
solana-sdk = { path = "../../sdk", version = "=1.7.0" } solana-sdk = { path = "../../sdk", version = "=1.7.0" }
solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" } solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" }

View File

@ -75,9 +75,12 @@ fn bench_program_create_executable(bencher: &mut Bencher) {
let elf = load_elf("bench_alu").unwrap(); let elf = load_elf("bench_alu").unwrap();
bencher.iter(|| { bencher.iter(|| {
let _ = let _ = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default()) &elf,
.unwrap(); None,
Config::default(),
)
.unwrap();
}); });
} }
@ -95,7 +98,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
let elf = load_elf("bench_alu").unwrap(); let elf = load_elf("bench_alu").unwrap();
let mut executable = let mut executable =
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default()) <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap(); .unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
executable.jit_compile().unwrap(); executable.jit_compile().unwrap();
@ -223,7 +226,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
let elf = load_elf("tuner").unwrap(); let elf = load_elf("tuner").unwrap();
let mut executable = let mut executable =
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default()) <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap(); .unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
let compute_meter = invoke_context.get_compute_meter(); let compute_meter = invoke_context.get_compute_meter();
@ -231,7 +234,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
let mut vm = create_vm( let mut vm = create_vm(
&loader_id, &loader_id,
executable.as_ref(), executable.as_ref(),
&mut serialized, serialized.as_slice_mut(),
&mut invoke_context, &mut invoke_context,
) )
.unwrap(); .unwrap();

View File

@ -217,7 +217,7 @@ fn run_program(
let mut vm = create_vm( let mut vm = create_vm(
&loader_id, &loader_id,
executable.as_ref(), executable.as_ref(),
&mut parameter_bytes, parameter_bytes.as_slice_mut(),
&mut invoke_context, &mut invoke_context,
) )
.unwrap(); .unwrap();
@ -256,7 +256,7 @@ fn run_program(
deserialize_parameters( deserialize_parameters(
&bpf_loader::id(), &bpf_loader::id(),
parameter_accounts, parameter_accounts,
&parameter_bytes, parameter_bytes.as_slice(),
true, true,
) )
.unwrap(); .unwrap();

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use solana_rbpf::{aligned_memory::AlignedMemory, ebpf::HOST_ALIGN};
use solana_sdk::{ use solana_sdk::{
account::ReadableAccount, bpf_loader_deprecated, entrypoint::MAX_PERMITTED_DATA_INCREASE, account::ReadableAccount, bpf_loader_deprecated, entrypoint::MAX_PERMITTED_DATA_INCREASE,
instruction::InstructionError, keyed_account::KeyedAccount, pubkey::Pubkey, instruction::InstructionError, keyed_account::KeyedAccount, pubkey::Pubkey,
@ -23,7 +24,7 @@ pub fn serialize_parameters(
program_id: &Pubkey, program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
data: &[u8], data: &[u8],
) -> Result<Vec<u8>, InstructionError> { ) -> Result<AlignedMemory, InstructionError> {
if *loader_id == bpf_loader_deprecated::id() { if *loader_id == bpf_loader_deprecated::id() {
serialize_parameters_unaligned(program_id, keyed_accounts, data) serialize_parameters_unaligned(program_id, keyed_accounts, data)
} else { } else {
@ -65,7 +66,7 @@ pub fn serialize_parameters_unaligned(
program_id: &Pubkey, program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
instruction_data: &[u8], instruction_data: &[u8],
) -> Result<Vec<u8>, InstructionError> { ) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once // Calculate size in order to alloc once
let mut size = size_of::<u64>(); let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() { for (i, keyed_account) in keyed_accounts.iter().enumerate() {
@ -78,7 +79,7 @@ pub fn serialize_parameters_unaligned(
size += size_of::<u64>() // instruction data len size += size_of::<u64>() // instruction data len
+ instruction_data.len() // instruction data + instruction_data.len() // instruction data
+ size_of::<Pubkey>(); // program id + 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) v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?; .map_err(|_| InstructionError::InvalidArgument)?;
@ -177,7 +178,7 @@ pub fn serialize_parameters_aligned(
program_id: &Pubkey, program_id: &Pubkey,
keyed_accounts: &[KeyedAccount], keyed_accounts: &[KeyedAccount],
instruction_data: &[u8], instruction_data: &[u8],
) -> Result<Vec<u8>, InstructionError> { ) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once // Calculate size in order to alloc once
let mut size = size_of::<u64>(); let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() { for (i, keyed_account) in keyed_accounts.iter().enumerate() {
@ -192,14 +193,11 @@ pub fn serialize_parameters_aligned(
size += size_of::<u64>() // data len size += size_of::<u64>() // data len
+ instruction_data.len() + instruction_data.len()
+ size_of::<Pubkey>(); // program id; + 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 // Serialize into the buffer
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64) v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?; .map_err(|_| InstructionError::InvalidArgument)?;
if v.as_ptr().align_offset(align_of::<u128>()) != 0 {
panic!();
}
for (i, keyed_account) in keyed_accounts.iter().enumerate() { for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account); let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account);
if is_dup { if is_dup {
@ -228,12 +226,12 @@ pub fn serialize_parameters_aligned(
.map_err(|_| InstructionError::InvalidArgument)?; .map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(&keyed_account.try_account_ref()?.data()) v.write_all(&keyed_account.try_account_ref()?.data())
.map_err(|_| InstructionError::InvalidArgument)?; .map_err(|_| InstructionError::InvalidArgument)?;
v.resize( v.fill(
v.len() MAX_PERMITTED_DATA_INCREASE
+ MAX_PERMITTED_DATA_INCREASE + (v.write_index() as *const u8).align_offset(align_of::<u128>()),
+ (v.len() as *const u8).align_offset(align_of::<u128>()),
0, 0,
); )
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64) v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64)
.map_err(|_| InstructionError::InvalidArgument)?; .map_err(|_| InstructionError::InvalidArgument)?;
} }
@ -410,7 +408,8 @@ mod tests {
.unwrap(); .unwrap();
let (de_program_id, de_accounts, de_instruction_data) = 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!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data); assert_eq!(instruction_data, de_instruction_data);
assert_eq!( assert_eq!(
@ -453,7 +452,13 @@ mod tests {
} }
}) })
.collect(); .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 for ((account, de_keyed_account), key) in
accounts.iter().zip(de_keyed_accounts).zip(keys.clone()) accounts.iter().zip(de_keyed_accounts).zip(keys.clone())
{ {
@ -480,7 +485,7 @@ mod tests {
.unwrap(); .unwrap();
let (de_program_id, de_accounts, de_instruction_data) = 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!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data); assert_eq!(instruction_data, de_instruction_data);
for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys.clone()) { for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys.clone()) {
@ -509,7 +514,7 @@ mod tests {
deserialize_parameters( deserialize_parameters(
&bpf_loader_deprecated::id(), &bpf_loader_deprecated::id(),
&de_keyed_accounts, &de_keyed_accounts,
&serialized, serialized.as_slice(),
true, true,
) )
.unwrap(); .unwrap();

File diff suppressed because it is too large Load Diff

View File

@ -135,6 +135,10 @@ pub mod check_duplicates_by_hash {
solana_sdk::declare_id!("8ZqTSYHgzyaYCcXJPMViRy6afCFSgNvYooPDeVdyj5GC"); solana_sdk::declare_id!("8ZqTSYHgzyaYCcXJPMViRy6afCFSgNvYooPDeVdyj5GC");
} }
pub mod enforce_aligned_host_addrs {
solana_sdk::declare_id!("6Qob9Z4RwGdf599FDVCqsjuKjR8ZFR3oVs2ByRLWBsua");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -156,8 +160,8 @@ lazy_static! {
(turbine_retransmit_peers_patch::id(), "turbine retransmit peers patch #14631"), (turbine_retransmit_peers_patch::id(), "turbine retransmit peers patch #14631"),
(require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"), (require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"),
(spl_token_v2_self_transfer_fix::id(), "spl-token self-transfer fix"), (spl_token_v2_self_transfer_fix::id(), "spl-token self-transfer fix"),
(full_inflation::mainnet::certusone::enable::id(), "Full inflation enabled by Certus One"), (full_inflation::mainnet::certusone::enable::id(), "full inflation enabled by Certus One"),
(full_inflation::mainnet::certusone::vote::id(), "Community vote allowing Certus One to enable full inflation"), (full_inflation::mainnet::certusone::vote::id(), "community vote allowing Certus One to enable full inflation"),
(warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"), (warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"),
(check_init_vote_data::id(), "check initialized Vote data"), (check_init_vote_data::id(), "check initialized Vote data"),
(check_program_owner::id(), "limit programs to operating on accounts owned by itself"), (check_program_owner::id(), "limit programs to operating on accounts owned by itself"),
@ -167,8 +171,9 @@ lazy_static! {
(cpi_data_cost::id(), "charge the compute budget for data passed via CPI"), (cpi_data_cost::id(), "charge the compute budget for data passed via CPI"),
(upgradeable_close_instruction::id(), "close upgradeable buffer accounts"), (upgradeable_close_instruction::id(), "close upgradeable buffer accounts"),
(demote_sysvar_write_locks::id(), "demote builtins and sysvar write locks to readonly #15497"), (demote_sysvar_write_locks::id(), "demote builtins and sysvar write locks to readonly #15497"),
(sysvar_via_syscall::id(), "Provide sysvars via syscalls"), (sysvar_via_syscall::id(), "provide sysvars via syscalls"),
(check_duplicates_by_hash::id(), "use transaction message hash for duplicate check"), (check_duplicates_by_hash::id(), "use transaction message hash for duplicate check"),
(enforce_aligned_host_addrs::id(), "enforce aligned host addresses"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()