Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Align host addresses (bp #11384) (#11817)
Browse files Browse the repository at this point in the history
* Align host addresses (#11384)

* Align host addresses

* support new program abi

* update epoch rollout

* Enforce aligned pointers in cross-program invocations

(cherry picked from commit 9290e56)

# Conflicts:
#	core/src/validator.rs
#	genesis-programs/src/lib.rs
#	programs/bpf_loader/src/deprecated.rs
#	programs/bpf_loader/src/lib.rs
#	sdk/src/entrypoint_native.rs
#	sdk/src/lib.rs

* resolve conflicts

* nudge

Co-authored-by: Jack May <jack@solana.com>
  • Loading branch information
mergify[bot] and jackcmay authored Aug 25, 2020
1 parent f3904b5 commit f162c6d
Show file tree
Hide file tree
Showing 14 changed files with 608 additions and 130 deletions.
9 changes: 5 additions & 4 deletions genesis-programs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option<Infl
OperatingMode::Stable => match epoch {
// No inflation at epoch 0
0 => Some(Inflation::new_disabled()),
// Inflation starts
// The epoch of Epoch::MAX is a placeholder and is expected to be reduced in
// a future hard fork.
// Inflation starts The epoch of Epoch::MAX is a placeholder and is
// expected to be reduced in a future hard fork.
Epoch::MAX => Some(Inflation::default()),
_ => None,
},
Expand All @@ -57,8 +56,10 @@ fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<Progr
match operating_mode {
OperatingMode::Development => {
if epoch == 0 {
// Programs used for testing
Some(vec![
Program::BuiltinLoader(solana_bpf_loader_program!()),
Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()),
Program::Native(solana_vest_program!()),
Program::Native(solana_budget_program!()),
Program::Native(solana_exchange_program!()),
Expand Down Expand Up @@ -179,7 +180,7 @@ mod tests {
fn test_development_programs() {
assert_eq!(
get_programs(OperatingMode::Development, 0).unwrap().len(),
4
5
);
assert!(get_programs(OperatingMode::Development, 1).is_none());
}
Expand Down
8 changes: 7 additions & 1 deletion local-cluster/tests/local_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,13 @@ fn test_stable_operating_mode() {
}

// Programs that are not available at epoch 0
for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() {
for program_id in [
&solana_sdk::bpf_loader::id(),
&solana_sdk::bpf_loader_deprecated::id(),
&solana_vest_program::id(),
]
.iter()
{
assert_eq!(
(
program_id,
Expand Down
5 changes: 5 additions & 0 deletions programs/bpf/c/src/invoked/invoked.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ extern uint64_t entrypoint(const uint8_t *input) {
sol_assert(sol_deserialize(input, &params, 4));

SolPubkey bpf_loader_id =
(SolPubkey){.x = {2, 168, 246, 145, 78, 136, 161, 110, 57, 90, 225,
40, 148, 143, 250, 105, 86, 147, 55, 104, 24, 221,
71, 67, 82, 33, 243, 198, 0, 0, 0, 0}};

SolPubkey bpf_loader_deprecated_id =
(SolPubkey){.x = {2, 168, 246, 145, 78, 136, 161, 107, 189, 35, 149,
133, 95, 100, 4, 217, 180, 244, 86, 183, 130, 27,
176, 20, 87, 73, 66, 140, 0, 0, 0, 0}};
Expand Down
181 changes: 103 additions & 78 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
pub mod alloc;
pub mod allocator_bump;
pub mod bpf_verifier;
pub mod deprecated;
pub mod serialization;
pub mod syscalls;

use crate::{bpf_verifier::VerifierError, syscalls::SyscallError};
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use crate::{
bpf_verifier::VerifierError,
serialization::{deserialize_parameters, serialize_parameters},
syscalls::SyscallError,
};
use num_derive::{FromPrimitive, ToPrimitive};
use solana_rbpf::{
ebpf::{EbpfError, UserDefinedError},
Expand All @@ -13,7 +18,7 @@ use solana_rbpf::{
};
use solana_sdk::{
account::{is_executable, next_keyed_account, KeyedAccount},
bpf_loader,
bpf_loader, bpf_loader_deprecated,
decode_error::DecodeError,
entrypoint::SUCCESS,
entrypoint_native::{ComputeMeter, InvokeContext},
Expand All @@ -22,7 +27,7 @@ use solana_sdk::{
program_utils::limited_deserialize,
pubkey::Pubkey,
};
use std::{cell::RefCell, io::prelude::*, mem, rc::Rc};
use std::{cell::RefCell, rc::Rc};
use thiserror::Error;

solana_sdk::declare_builtin!(
Expand Down Expand Up @@ -85,75 +90,6 @@ pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool,
(false, 0)
}

pub fn serialize_parameters(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
) -> Result<Vec<u8>, InstructionError> {
assert_eq!(32, mem::size_of::<Pubkey>());

let mut v: Vec<u8> = Vec::new();
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.unwrap();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account);
if is_dup {
v.write_u8(position as u8).unwrap();
} else {
v.write_u8(std::u8::MAX).unwrap();
v.write_u8(keyed_account.signer_key().is_some() as u8)
.unwrap();
v.write_u8(keyed_account.is_writable() as u8).unwrap();
v.write_all(keyed_account.unsigned_key().as_ref()).unwrap();
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
.unwrap();
v.write_u64::<LittleEndian>(keyed_account.data_len()? as u64)
.unwrap();
v.write_all(&keyed_account.try_account_ref()?.data).unwrap();
v.write_all(keyed_account.owner()?.as_ref()).unwrap();
v.write_u8(keyed_account.executable()? as u8).unwrap();
v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64)
.unwrap();
}
}
v.write_u64::<LittleEndian>(data.len() as u64).unwrap();
v.write_all(data).unwrap();
v.write_all(program_id.as_ref()).unwrap();
Ok(v)
}

pub fn deserialize_parameters(
keyed_accounts: &[KeyedAccount],
buffer: &[u8],
) -> Result<(), InstructionError> {
assert_eq!(32, mem::size_of::<Pubkey>());

let mut start = mem::size_of::<u64>(); // number of accounts
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account);
start += 1; // is_dup
if !is_dup {
start += mem::size_of::<u8>(); // is_signer
start += mem::size_of::<u8>(); // is_writable
start += mem::size_of::<Pubkey>(); // pubkey
keyed_account.try_account_ref_mut()?.lamports =
LittleEndian::read_u64(&buffer[start..]);
start += mem::size_of::<u64>() // lamports
+ mem::size_of::<u64>(); // data length
let end = start + keyed_account.data_len()?;
keyed_account
.try_account_ref_mut()?
.data
.clone_from_slice(&buffer[start..end]);
start += keyed_account.data_len()? // data
+ mem::size_of::<Pubkey>() // owner
+ mem::size_of::<u8>() // executable
+ mem::size_of::<u64>(); // rent_epoch
}
}
Ok(())
}

macro_rules! log{
($logger:ident, $message:expr) => {
if let Ok(mut logger) = $logger.try_borrow_mut() {
Expand Down Expand Up @@ -189,7 +125,7 @@ pub fn process_instruction(
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
debug_assert!(bpf_loader::check_id(program_id));
debug_assert!(bpf_loader::check_id(program_id) || bpf_loader_deprecated::check_id(program_id));

let logger = invoke_context.get_logger();

Expand All @@ -204,6 +140,7 @@ pub fn process_instruction(

let parameter_accounts = keyed_accounts_iter.as_slice();
let parameter_bytes = serialize_parameters(
program_id,
program.unsigned_key(),
parameter_accounts,
&instruction_data,
Expand Down Expand Up @@ -256,7 +193,7 @@ pub fn process_instruction(
}
}
}
deserialize_parameters(parameter_accounts, &parameter_bytes)?;
deserialize_parameters(program_id, parameter_accounts, &parameter_bytes)?;
log!(logger, "BPF program {} success", program.unsigned_key());
} else if !keyed_accounts.is_empty() {
match limited_deserialize(instruction_data)? {
Expand Down Expand Up @@ -496,7 +433,7 @@ mod tests {
fn test_bpf_loader_finalize() {
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new();
let rent = Rent::default();
file.read_to_end(&mut elf).unwrap();
Expand Down Expand Up @@ -562,7 +499,7 @@ mod tests {
let program_key = Pubkey::new_rand();

// Create program account
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
let program_account = Account::new_ref(1, 0, &program_id);
Expand Down Expand Up @@ -636,6 +573,94 @@ mod tests {
);
}

#[test]
fn test_bpf_loader_serialize_unaligned() {
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();

// Create program account
let mut file = File::open("test_elfs/noop_unaligned.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
let program_account = Account::new_ref(1, 0, &program_id);
program_account.borrow_mut().data = elf;
program_account.borrow_mut().executable = true;
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];

// Case: With program and parameter account
let parameter_account = Account::new_ref(1, 0, &program_id);
keyed_accounts.push(KeyedAccount::new(&program_key, false, &parameter_account));
assert_eq!(
Ok(()),
process_instruction(
&bpf_loader_deprecated::id(),
&keyed_accounts,
&[],
&mut MockInvokeContext::default()
)
);

// Case: With duplicate accounts
let duplicate_key = Pubkey::new_rand();
let parameter_account = Account::new_ref(1, 0, &program_id);
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
assert_eq!(
Ok(()),
process_instruction(
&bpf_loader_deprecated::id(),
&keyed_accounts,
&[],
&mut MockInvokeContext::default()
)
);
}

#[test]
fn test_bpf_loader_serialize_aligned() {
let program_id = Pubkey::new_rand();
let program_key = Pubkey::new_rand();

// Create program account
let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
let program_account = Account::new_ref(1, 0, &program_id);
program_account.borrow_mut().data = elf;
program_account.borrow_mut().executable = true;
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];

// Case: With program and parameter account
let parameter_account = Account::new_ref(1, 0, &program_id);
keyed_accounts.push(KeyedAccount::new(&program_key, false, &parameter_account));
assert_eq!(
Ok(()),
process_instruction(
&bpf_loader::id(),
&keyed_accounts,
&[],
&mut MockInvokeContext::default()
)
);

// Case: With duplicate accounts
let duplicate_key = Pubkey::new_rand();
let parameter_account = Account::new_ref(1, 0, &program_id);
let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)];
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, &parameter_account));
assert_eq!(
Ok(()),
process_instruction(
&bpf_loader::id(),
&keyed_accounts,
&[],
&mut MockInvokeContext::default()
)
);
}

/// fuzzing utility function
fn fuzz<F>(
bytes: &[u8],
Expand Down Expand Up @@ -666,7 +691,7 @@ mod tests {
let program_key = Pubkey::new_rand();

// Create program account
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();

Expand Down
Loading

0 comments on commit f162c6d

Please sign in to comment.