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]]
name = "solana_rbpf"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14e36c51d5aa290416c5dea3c43ac467cb57c0b643184af23e6bdab7434710fb"
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
dependencies = [
"byteorder",
"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-logger = { path = "../logger", 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-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }

View File

@ -3595,9 +3595,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14e36c51d5aa290416c5dea3c43ac467cb57c0b643184af23e6bdab7434710fb"
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
dependencies = [
"byteorder 1.3.4",
"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-logger = { path = "../../logger", 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-sdk = { path = "../../sdk", 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();
bencher.iter(|| {
let _ =
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
let _ = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
)
.unwrap();
});
}
@ -95,7 +98,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
let elf = load_elf("bench_alu").unwrap();
let mut executable =
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
<dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
executable.jit_compile().unwrap();
@ -223,7 +226,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
let elf = load_elf("tuner").unwrap();
let mut executable =
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
<dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
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(
&loader_id,
executable.as_ref(),
&mut serialized,
serialized.as_slice_mut(),
&mut invoke_context,
)
.unwrap();

View File

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

View File

@ -20,7 +20,7 @@ rand_core = "0.6.2"
solana-measure = { path = "../../measure", version = "=1.7.0" }
solana-runtime = { path = "../../runtime", 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"
[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},
@ -147,8 +148,8 @@ pub fn create_vm<'a>(
parameter_bytes: &mut [u8],
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, &mut vm, invoke_context, heap)?;
Ok(vm)
@ -759,7 +760,7 @@ impl Executor for BpfExecutor {
let mut vm = match create_vm(
loader_id,
self.executable.as_ref(),
&mut parameter_bytes,
parameter_bytes.as_slice_mut(),
invoke_context,
) {
Ok(info) => info,
@ -823,7 +824,7 @@ impl Executor for BpfExecutor {
deserialize_parameters(
loader_id,
keyed_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, bpf_loader_deprecated, entrypoint::MAX_PERMITTED_DATA_INCREASE,
instruction::InstructionError, keyed_account::KeyedAccount, pubkey::Pubkey,
@ -23,7 +24,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 {
@ -65,7 +66,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() {
@ -78,7 +79,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)?;
@ -177,7 +178,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() {
@ -192,14 +193,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 {
@ -228,12 +226,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)?;
}
@ -410,7 +408,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!(
@ -453,7 +452,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())
{
@ -480,7 +485,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()) {
@ -509,7 +514,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

View File

@ -135,6 +135,10 @@ pub mod check_duplicates_by_hash {
solana_sdk::declare_id!("8ZqTSYHgzyaYCcXJPMViRy6afCFSgNvYooPDeVdyj5GC");
}
pub mod enforce_aligned_host_addrs {
solana_sdk::declare_id!("6Qob9Z4RwGdf599FDVCqsjuKjR8ZFR3oVs2ByRLWBsua");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
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"),
(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"),
(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::enable::id(), "full inflation enabled by Certus One"),
(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"),
(check_init_vote_data::id(), "check initialized Vote data"),
(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"),
(upgradeable_close_instruction::id(), "close upgradeable buffer accounts"),
(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"),
(enforce_aligned_host_addrs::id(), "enforce aligned host addresses"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()