From eeb7503fb6aba14baf51ee5ab6f8f1c7eae753c2 Mon Sep 17 00:00:00 2001 From: Jack May Date: Thu, 27 Aug 2020 09:19:05 -0700 Subject: [PATCH] Revert "Align host addresses (#11384) (#11836)" (#11876) This reverts commit 3296c13ef2999e1fc8391f8fa61145971f9e2d9a. --- core/src/validator.rs | 3 - genesis-programs/src/lib.rs | 38 +- local-cluster/tests/local_cluster.rs | 8 +- programs/bpf/c/src/invoked/invoked.c | 5 - programs/bpf_loader/src/deprecated.rs | 9 - programs/bpf_loader/src/lib.rs | 184 ++++---- programs/bpf_loader/src/serialization.rs | 410 ------------------ programs/bpf_loader/src/syscalls.rs | 68 ++- .../test_elfs/{noop_unaligned.so => noop.so} | Bin programs/bpf_loader/test_elfs/noop_aligned.so | Bin 58088 -> 0 bytes sdk/bpf/c/inc/solana_sdk.h | 37 +- sdk/src/bpf_loader.rs | 2 +- sdk/src/bpf_loader_deprecated.rs | 1 - sdk/src/entrypoint.rs | 18 +- sdk/src/entrypoint_native.rs | 34 +- sdk/src/lib.rs | 1 - 16 files changed, 163 insertions(+), 655 deletions(-) delete mode 100644 programs/bpf_loader/src/deprecated.rs delete mode 100644 programs/bpf_loader/src/serialization.rs rename programs/bpf_loader/test_elfs/{noop_unaligned.so => noop.so} (100%) delete mode 100755 programs/bpf_loader/test_elfs/noop_aligned.so delete mode 100644 sdk/src/bpf_loader_deprecated.rs diff --git a/core/src/validator.rs b/core/src/validator.rs index be30f05e02..8b3d1dd9fb 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -863,9 +863,6 @@ impl TestValidator { genesis_config .native_instruction_processors .push(solana_bpf_loader_program!()); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_deprecated_program!()); genesis_config.rent.lamports_per_byte_year = 1; genesis_config.rent.exemption_threshold = 1.0; diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs index 86d2935d38..ca951cee03 100644 --- a/genesis-programs/src/lib.rs +++ b/genesis-programs/src/lib.rs @@ -36,8 +36,9 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option 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, }, @@ -48,36 +49,38 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option { if epoch == 0 { - // Programs used for testing Some(vec![ + // Enable all Stable programs solana_bpf_loader_program!(), - solana_bpf_loader_deprecated_program!(), solana_vest_program!(), + // Programs that are only available in Development mode solana_budget_program!(), solana_exchange_program!(), ]) - } else if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!()]) } else { None } } OperatingMode::Stable => { - if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!(), solana_vest_program!()]) + if epoch == std::u64::MAX - 1 { + // The epoch of std::u64::MAX - 1 is a placeholder and is expected to be reduced in + // a future hard fork. + Some(vec![solana_bpf_loader_program!()]) + } else if epoch == std::u64::MAX { + // The epoch of std::u64::MAX is a placeholder and is expected to be reduced in a + // future hard fork. + Some(vec![solana_vest_program!()]) } else { None } } OperatingMode::Preview => { - if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!(), solana_vest_program!()]) + if epoch == 0 { + Some(vec![solana_bpf_loader_program!()]) + } else if epoch == std::u64::MAX { + // The epoch of std::u64::MAX is a placeholder and is expected to be reduced in a + // future hard fork. + Some(vec![solana_vest_program!()]) } else { None } @@ -135,7 +138,7 @@ mod tests { fn test_development_programs() { assert_eq!( get_programs(OperatingMode::Development, 0).unwrap().len(), - 5 + 4 ); assert_eq!(get_programs(OperatingMode::Development, 1), None); } @@ -156,6 +159,7 @@ mod tests { #[test] fn test_softlaunch_programs() { assert_eq!(get_programs(OperatingMode::Stable, 1), None); + assert!(get_programs(OperatingMode::Stable, std::u64::MAX - 1).is_some()); assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some()); } } diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index 07f1adc3e6..2da53aca94 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -562,13 +562,7 @@ fn test_stable_operating_mode() { } // Programs that are not available at epoch 0 - for program_id in [ - &solana_sdk::bpf_loader::id(), - &solana_sdk::bpf_loader_deprecated::id(), - &solana_vest_program::id(), - ] - .iter() - { + for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() { assert_eq!( ( program_id, diff --git a/programs/bpf/c/src/invoked/invoked.c b/programs/bpf/c/src/invoked/invoked.c index db6473f826..3e72256a60 100644 --- a/programs/bpf/c/src/invoked/invoked.c +++ b/programs/bpf/c/src/invoked/invoked.c @@ -23,11 +23,6 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert(sol_deserialize(input, ¶ms, 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}}; diff --git a/programs/bpf_loader/src/deprecated.rs b/programs/bpf_loader/src/deprecated.rs deleted file mode 100644 index b2564c9ad1..0000000000 --- a/programs/bpf_loader/src/deprecated.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::process_instruction; - -solana_sdk::declare_loader!( - solana_sdk::bpf_loader_deprecated::ID, - solana_bpf_loader_deprecated_program, - process_instruction, - solana_bpf_loader_program, - deprecated::id -); diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index eb3d01ac2a..90553572d4 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1,15 +1,10 @@ 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, - serialization::{deserialize_parameters, serialize_parameters}, - syscalls::SyscallError, -}; +use crate::{bpf_verifier::VerifierError, syscalls::SyscallError}; +use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; use num_derive::{FromPrimitive, ToPrimitive}; use solana_rbpf::{ ebpf::{EbpfError, UserDefinedError}, @@ -18,7 +13,7 @@ use solana_rbpf::{ }; use solana_sdk::{ account::{is_executable, next_keyed_account, KeyedAccount}, - bpf_loader, bpf_loader_deprecated, + bpf_loader, decode_error::DecodeError, entrypoint::SUCCESS, entrypoint_native::InvokeContext, @@ -27,13 +22,13 @@ use solana_sdk::{ program_utils::limited_deserialize, pubkey::Pubkey, }; +use std::{io::prelude::*, mem}; use thiserror::Error; solana_sdk::declare_loader!( solana_sdk::bpf_loader::ID, solana_bpf_loader_program, - process_instruction, - solana_bpf_loader_program + process_instruction ); #[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] @@ -91,6 +86,75 @@ 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, InstructionError> { + assert_eq!(32, mem::size_of::()); + + let mut v: Vec = Vec::new(); + v.write_u64::(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::(keyed_account.lamports()?) + .unwrap(); + v.write_u64::(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::(keyed_account.rent_epoch()? as u64) + .unwrap(); + } + } + v.write_u64::(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::()); + + let mut start = mem::size_of::(); // 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::(); // is_signer + start += mem::size_of::(); // is_writable + start += mem::size_of::(); // pubkey + keyed_account.try_account_ref_mut()?.lamports = + LittleEndian::read_u64(&buffer[start..]); + start += mem::size_of::() // lamports + + mem::size_of::(); // 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::() // owner + + mem::size_of::() // executable + + mem::size_of::(); // rent_epoch + } + } + Ok(()) +} + macro_rules! log{ ($logger:ident, $message:expr) => { if let Ok(mut logger) = $logger.try_borrow_mut() { @@ -112,7 +176,7 @@ pub fn process_instruction( instruction_data: &[u8], invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { - debug_assert!(bpf_loader::check_id(program_id) || bpf_loader_deprecated::check_id(program_id)); + debug_assert!(bpf_loader::check_id(program_id)); let logger = invoke_context.get_logger(); @@ -127,7 +191,6 @@ 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, @@ -173,7 +236,7 @@ pub fn process_instruction( } } } - deserialize_parameters(program_id, parameter_accounts, ¶meter_bytes)?; + deserialize_parameters(parameter_accounts, ¶meter_bytes)?; log!(logger, "BPF program {} success", program.unsigned_key()); } else if !keyed_accounts.is_empty() { match limited_deserialize(instruction_data)? { @@ -286,7 +349,6 @@ mod tests { // Ensure that we can invoke this macro from the same crate // where it is defined. solana_bpf_loader_program!(); - solana_bpf_loader_deprecated_program!(); } #[test] @@ -376,7 +438,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_aligned.so").expect("file open failed"); + let mut file = File::open("test_elfs/noop.so").expect("file open failed"); let mut elf = Vec::new(); let rent = Rent::default(); file.read_to_end(&mut elf).unwrap(); @@ -442,7 +504,7 @@ mod tests { 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 file = File::open("test_elfs/noop.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); @@ -516,94 +578,6 @@ 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, ¶meter_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, ¶meter_account)); - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_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, ¶meter_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, ¶meter_account)); - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); - assert_eq!( - Ok(()), - process_instruction( - &bpf_loader::id(), - &keyed_accounts, - &[], - &mut MockInvokeContext::default() - ) - ); - } - /// fuzzing utility function fn fuzz( bytes: &[u8], @@ -634,7 +608,7 @@ mod tests { 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 file = File::open("test_elfs/noop.so").expect("file open failed"); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs deleted file mode 100644 index 87137efa1a..0000000000 --- a/programs/bpf_loader/src/serialization.rs +++ /dev/null @@ -1,410 +0,0 @@ -use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; -use solana_sdk::{ - account::KeyedAccount, bpf_loader_deprecated, instruction::InstructionError, pubkey::Pubkey, -}; -use std::{ - io::prelude::*, - mem::{self, align_of}, -}; - -/// Look for a duplicate account and return its position if found -pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool, usize) { - for (i, account) in accounts.iter().enumerate() { - if account == keyed_account { - return (true, i); - } - } - (false, 0) -} - -pub fn serialize_parameters( - loader_id: &Pubkey, - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - data: &[u8], -) -> Result, InstructionError> { - if *loader_id == bpf_loader_deprecated::id() { - serialize_parameters_unaligned(program_id, keyed_accounts, data) - } else { - serialize_parameters_aligned(program_id, keyed_accounts, data) - } -} - -pub fn deserialize_parameters( - loader_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - if *loader_id == bpf_loader_deprecated::id() { - deserialize_parameters_unaligned(keyed_accounts, buffer) - } else { - deserialize_parameters_aligned(keyed_accounts, buffer) - } -} - -pub fn serialize_parameters_unaligned( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> Result, InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut v: Vec = Vec::new(); - v.write_u64::(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::(keyed_account.lamports()?) - .unwrap(); - v.write_u64::(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::(keyed_account.rent_epoch()? as u64) - .unwrap(); - } - } - v.write_u64::(instruction_data.len() as u64) - .unwrap(); - v.write_all(instruction_data).unwrap(); - v.write_all(program_id.as_ref()).unwrap(); - Ok(v) -} - -pub fn deserialize_parameters_unaligned( - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut start = mem::size_of::(); // 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::(); // is_signer - start += mem::size_of::(); // is_writable - start += mem::size_of::(); // pubkey - keyed_account.try_account_ref_mut()?.lamports = - LittleEndian::read_u64(&buffer[start..]); - start += mem::size_of::() // lamports - + mem::size_of::(); // 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::() // owner - + mem::size_of::() // executable - + mem::size_of::(); // rent_epoch - } - } - Ok(()) -} - -pub fn serialize_parameters_aligned( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> Result, InstructionError> { - assert_eq!(32, mem::size_of::()); - - // TODO use with capacity would be nice, but don't know account data sizes... - let mut v: Vec = Vec::new(); - v.write_u64::(keyed_accounts.len() as u64) - .unwrap(); - - // TODO panic? - if v.as_ptr().align_offset(align_of::()) != 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 { - v.write_u8(position as u8).unwrap(); - v.write_all(&[0u8, 0, 0, 0, 0, 0, 0]).unwrap(); // 7 bytes of padding to make 64-bit aligned - } 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_u8(keyed_account.executable()? as u8).unwrap(); - v.write_all(&[0u8, 0, 0, 0]).unwrap(); // 4 bytes of padding to make 128-bit aligned - v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); - v.write_all(keyed_account.owner()?.as_ref()).unwrap(); - v.write_u64::(keyed_account.lamports()?) - .unwrap(); - v.write_u64::(keyed_account.data_len()? as u64) - .unwrap(); - v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); - for _ in 0..16 - (v.len() % 16) { - v.write_u8(0).unwrap(); // 128 bit aligned again - } - v.write_u64::(keyed_account.rent_epoch()? as u64) - .unwrap(); - } - } - v.write_u64::(instruction_data.len() as u64) - .unwrap(); - v.write_all(instruction_data).unwrap(); - v.write_all(program_id.as_ref()).unwrap(); - Ok(v) -} - -pub fn deserialize_parameters_aligned( - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut start = mem::size_of::(); // 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::() // is_signer - + mem::size_of::() // is_writable - + mem::size_of::() // executable - + 4 // padding - + mem::size_of::() // pubkey - + mem::size_of::(); // owner - keyed_account.try_account_ref_mut()?.lamports = - LittleEndian::read_u64(&buffer[start..]); - start += mem::size_of::() // lamports - + mem::size_of::(); // 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 - start += 16 - (start % 16); // padding - start += mem::size_of::(); // rent_epoch - } else { - start += 7; // padding - } - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use solana_sdk::{ - account::Account, account_info::AccountInfo, bpf_loader, entrypoint::deserialize, - }; - use std::{ - cell::RefCell, - mem::size_of, - rc::Rc, - // Hide Result from bindgen gets confused about generics in non-generic type declarations - slice::{from_raw_parts, from_raw_parts_mut}, - }; - - #[test] - fn test_serialize_parameters() { - let program_id = Pubkey::new_rand(); - let dup_key = Pubkey::new_rand(); - let keys = vec![dup_key, dup_key, Pubkey::new_rand(), Pubkey::new_rand()]; - let accounts = [ - RefCell::new(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }), - // dup of first - RefCell::new(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }), - RefCell::new(Account { - lamports: 2, - data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], - owner: bpf_loader::id(), - executable: true, - rent_epoch: 200, - }), - RefCell::new(Account { - lamports: 3, - data: vec![], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 3100, - }), - ]; - - let keyed_accounts: Vec<_> = keys - .iter() - .zip(&accounts) - .map(|(key, account)| KeyedAccount::new(&key, false, &account)) - .collect(); - let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - - // check serialize_parameters_aligned - - let mut serialized = serialize_parameters( - &bpf_loader::id(), - &program_id, - &keyed_accounts, - &instruction_data, - ) - .unwrap(); - let (de_program_id, de_accounts, de_instruction_data) = - unsafe { deserialize(&mut serialized[0] as *mut u8) }; - - assert_eq!(&program_id, de_program_id); - assert_eq!(instruction_data, de_instruction_data); - assert_eq!( - (&de_instruction_data[0] as *const u8).align_offset(align_of::()), - 0 - ); - for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys.clone()) { - assert_eq!(key, *account_info.key); - let account = account.borrow(); - assert_eq!(account.lamports, account_info.lamports()); - assert_eq!(&account.data[..], &account_info.data.borrow()[..]); - assert_eq!(&account.owner, account_info.owner); - assert_eq!(account.executable, account_info.executable); - assert_eq!(account.rent_epoch, account_info.rent_epoch); - - assert_eq!( - (*account_info.lamports.borrow() as *const u64).align_offset(align_of::()), - 0 - ); - assert_eq!( - account_info - .data - .borrow() - .as_ptr() - .align_offset(align_of::()), - 0 - ); - } - - // check serialize_parameters_unaligned - - let mut serialized = serialize_parameters( - &bpf_loader_deprecated::id(), - &program_id, - &keyed_accounts, - &instruction_data, - ) - .unwrap(); - let (de_program_id, de_accounts, de_instruction_data) = - unsafe { deserialize_unaligned(&mut serialized[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) { - assert_eq!(key, *account_info.key); - let account = account.borrow(); - assert_eq!(account.lamports, account_info.lamports()); - assert_eq!(&account.data[..], &account_info.data.borrow()[..]); - assert_eq!(&account.owner, account_info.owner); - assert_eq!(account.executable, account_info.executable); - assert_eq!(account.rent_epoch, account_info.rent_epoch); - } - } - - // the old bpf_loader in-program deserializer bpf_loader::id() - #[allow(clippy::type_complexity)] - pub unsafe fn deserialize_unaligned<'a>( - input: *mut u8, - ) -> (&'a Pubkey, Vec>, &'a [u8]) { - let mut offset: usize = 0; - - // number of accounts present - - #[allow(clippy::cast_ptr_alignment)] - let num_accounts = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - // account Infos - - let mut accounts = Vec::with_capacity(num_accounts); - for _ in 0..num_accounts { - let dup_info = *(input.add(offset) as *const u8); - offset += size_of::(); - if dup_info == std::u8::MAX { - #[allow(clippy::cast_ptr_alignment)] - let is_signer = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let is_writable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - let key: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let data_len = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - let data = Rc::new(RefCell::new({ - from_raw_parts_mut(input.add(offset), data_len) - })); - offset += data_len; - - let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let executable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let rent_epoch = *(input.add(offset) as *const u64); - offset += size_of::(); - - accounts.push(AccountInfo { - is_signer, - is_writable, - key, - lamports, - data, - owner, - executable, - rent_epoch, - }); - } else { - // duplicate account, clone the original - accounts.push(accounts[dup_info as usize].clone()); - } - } - - // instruction data - - #[allow(clippy::cast_ptr_alignment)] - let instruction_data_len = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) }; - offset += instruction_data_len; - - // program Id - - let program_id: &Pubkey = &*(input.add(offset) as *const Pubkey); - - (program_id, accounts, instruction_data) - } -} diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 51d7f8e445..b2adc123ef 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -50,8 +50,6 @@ pub enum SyscallError { InstructionError(InstructionError), #[error("Cross-program invocation with unauthorized signer or writable account")] PrivilegeEscalation, - #[error("Unaligned pointer")] - UnalignedPointer, } impl From for EbpfError { fn from(error: SyscallError) -> Self { @@ -143,24 +141,20 @@ macro_rules! translate { #[macro_export] macro_rules! translate_type_mut { - ($t:ty, $vm_addr:expr, $regions:expr) => {{ - if ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 { - Err(SyscallError::UnalignedPointer.into()) - } else { - unsafe { - match translate_addr::( - $vm_addr as u64, - size_of::<$t>(), - file!(), - line!() as usize - ELF_INSN_DUMP_OFFSET + 1, - $regions, - ) { - Ok(value) => Ok(&mut *(value as *mut $t)), - Err(e) => Err(e), - } + ($t:ty, $vm_addr:expr, $regions:expr) => { + unsafe { + match translate_addr::( + $vm_addr as u64, + size_of::<$t>(), + file!(), + line!() as usize - ELF_INSN_DUMP_OFFSET + 1, + $regions, + ) { + Ok(value) => Ok(&mut *(value as *mut $t)), + Err(e) => Err(e), } } - }}; + }; } #[macro_export] macro_rules! translate_type { @@ -174,22 +168,18 @@ macro_rules! translate_type { #[macro_export] macro_rules! translate_slice_mut { - ($t:ty, $vm_addr:expr, $len: expr, $regions:expr) => {{ - if ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 { - Err(SyscallError::UnalignedPointer.into()) - } else { - match translate_addr::( - $vm_addr as u64, - $len as usize * size_of::<$t>(), - file!(), - line!() as usize - ELF_INSN_DUMP_OFFSET + 1, - $regions, - ) { - Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }), - Err(e) => Err(e), - } + ($t:ty, $vm_addr:expr, $len: expr, $regions:expr) => { + match translate_addr::( + $vm_addr as u64, + $len as usize * size_of::<$t>(), + file!(), + line!() as usize - ELF_INSN_DUMP_OFFSET + 1, + $regions, + ) { + Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }), + Err(e) => Err(e), } - }}; + }; } #[macro_export] macro_rules! translate_slice { @@ -469,7 +459,7 @@ impl<'a> SyscallProcessInstruction<'a> for SyscallProcessInstructionRust<'a> { let lamports_ref = { // Double translate lamports out of RefCell let ptr = translate_type!(u64, account_info.lamports.as_ptr(), ro_regions)?; - translate_type_mut!(u64, *ptr, rw_regions)? + translate_type_mut!(u64, *(ptr as *const u64), rw_regions)? }; let data = { // Double translate data out of RefCell @@ -931,17 +921,13 @@ mod tests { vec![AccountMeta::new(Pubkey::new_rand(), false)], ); let addr = &instruction as *const _ as u64; - let mut regions = vec![MemoryRegion { + let regions = vec![MemoryRegion { addr_host: addr, - addr_vm: 96, + addr_vm: 100, len: std::mem::size_of::() as u64, }]; - let translated_instruction = translate_type!(Instruction, 96, ®ions).unwrap(); + let translated_instruction = translate_type!(Instruction, 100, ®ions).unwrap(); assert_eq!(instruction, *translated_instruction); - regions[0].len = 1; - assert!(translate_type!(Instruction, 100, ®ions).is_err()); - regions[0].len = std::mem::size_of::() as u64 * 2; - assert!(translate_type!(Instruction, 100, ®ions).is_err()); } #[test] diff --git a/programs/bpf_loader/test_elfs/noop_unaligned.so b/programs/bpf_loader/test_elfs/noop.so similarity index 100% rename from programs/bpf_loader/test_elfs/noop_unaligned.so rename to programs/bpf_loader/test_elfs/noop.so diff --git a/programs/bpf_loader/test_elfs/noop_aligned.so b/programs/bpf_loader/test_elfs/noop_aligned.so deleted file mode 100755 index 28bbdc0980a7023ccb04591967638007c3d82d1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58088 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

i3Iscm&~-rKfB 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 upUAUKl6U;~a1^Keo8%f{&_5Xivok+w0 diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index f9c9c2ad59..305a8b4aa6 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -290,15 +290,12 @@ static bool sol_deserialize( if (dup_info == UINT8_MAX) { input += sizeof(uint8_t); input += sizeof(uint8_t); + input += sizeof(SolPubkey); + input += sizeof(uint64_t); + input += *(uint64_t *) input; + input += sizeof(uint64_t); + input += sizeof(SolPubkey); input += sizeof(uint8_t); - input += 4; // padding - input += sizeof(SolPubkey); - input += sizeof(SolPubkey); - input += sizeof(uint64_t); - uint64_t data_len = *(uint64_t *) input; - input += sizeof(uint64_t); - input += data_len; - input += 16 - (data_len % 16); // padding input += sizeof(uint64_t); } continue; @@ -312,20 +309,10 @@ static bool sol_deserialize( params->ka[i].is_writable = *(uint8_t *) input != 0; input += sizeof(uint8_t); - // executable? - params->ka[i].executable = *(uint8_t *) input; - input += sizeof(uint8_t); - - input += 4; // padding - // key params->ka[i].key = (SolPubkey *) input; input += sizeof(SolPubkey); - // owner - params->ka[i].owner = (SolPubkey *) input; - input += sizeof(SolPubkey); - // lamports params->ka[i].lamports = (uint64_t *) input; input += sizeof(uint64_t); @@ -336,22 +323,26 @@ static bool sol_deserialize( params->ka[i].data = (uint8_t *) input; input += params->ka[i].data_len; - input += 16 - (params->ka[i].data_len % 16); // padding + // owner + params->ka[i].owner = (SolPubkey *) input; + input += sizeof(SolPubkey); + + // executable? + params->ka[i].executable = *(uint8_t *) input; + input += sizeof(uint8_t); // rent epoch params->ka[i].rent_epoch = *(uint64_t *) input; input += sizeof(uint64_t); } else { params->ka[i].is_signer = params->ka[dup_info].is_signer; - params->ka[i].is_writable = params->ka[dup_info].is_writable; - params->ka[i].executable = params->ka[dup_info].executable; params->ka[i].key = params->ka[dup_info].key; - params->ka[i].owner = params->ka[dup_info].owner; params->ka[i].lamports = params->ka[dup_info].lamports; params->ka[i].data_len = params->ka[dup_info].data_len; params->ka[i].data = params->ka[dup_info].data; + params->ka[i].owner = params->ka[dup_info].owner; + params->ka[i].executable = params->ka[dup_info].executable; params->ka[i].rent_epoch = params->ka[dup_info].rent_epoch; - input += 7; // padding } } diff --git a/sdk/src/bpf_loader.rs b/sdk/src/bpf_loader.rs index cf6fa767b9..33461caa0a 100644 --- a/sdk/src/bpf_loader.rs +++ b/sdk/src/bpf_loader.rs @@ -1 +1 @@ -crate::declare_id!("BPFLoader2111111111111111111111111111111111"); +crate::declare_id!("BPFLoader1111111111111111111111111111111111"); diff --git a/sdk/src/bpf_loader_deprecated.rs b/sdk/src/bpf_loader_deprecated.rs deleted file mode 100644 index 33461caa0a..0000000000 --- a/sdk/src/bpf_loader_deprecated.rs +++ /dev/null @@ -1 +0,0 @@ -crate::declare_id!("BPFLoader1111111111111111111111111111111111"); diff --git a/sdk/src/entrypoint.rs b/sdk/src/entrypoint.rs index 6be53a323d..5bc7da2ab3 100644 --- a/sdk/src/entrypoint.rs +++ b/sdk/src/entrypoint.rs @@ -76,18 +76,9 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); - #[allow(clippy::cast_ptr_alignment)] - let executable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - offset += 4; // padding - let key: &Pubkey = &*(input.add(offset) as *const Pubkey); offset += size_of::(); - let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - #[allow(clippy::cast_ptr_alignment)] let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); offset += size_of::(); @@ -101,7 +92,12 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); + + #[allow(clippy::cast_ptr_alignment)] + let executable = *(input.add(offset) as *const u8) != 0; + offset += size_of::(); #[allow(clippy::cast_ptr_alignment)] let rent_epoch = *(input.add(offset) as *const u64); @@ -118,8 +114,6 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec { + ($name:ident) => { #[macro_export] macro_rules! $name { () => { @@ -66,8 +66,8 @@ macro_rules! declare_name { // `respan!` respans the path `$crate::id`, which we then call (hence the extra // parens) ( - stringify!($filename).to_string(), - ::solana_sdk::respan!($crate::$id, $name)(), + stringify!($name).to_string(), + ::solana_sdk::respan!($crate::id, $name)(), ) }; } @@ -77,11 +77,11 @@ macro_rules! declare_name { #[rustversion::not(since(1.46.0))] #[macro_export] macro_rules! declare_name { - ($name:ident, $filename:ident, $id:path) => { + ($name:ident) => { #[macro_export] macro_rules! $name { () => { - (stringify!($filename).to_string(), $crate::$id()) + (stringify!($name).to_string(), $crate::id()) }; } }; @@ -90,10 +90,8 @@ macro_rules! declare_name { /// Convenience macro to declare a native program /// /// bs58_string: bs58 string representation the program's id -/// name: Name of the program -/// filename: must match the library name in Cargo.toml +/// name: Name of the program, must match the library name in Cargo.toml /// entrypoint: Program's entrypoint, must be of `type Entrypoint` -/// id: Path to the program id access function, used if not called in `src/lib` /// /// # Examples /// @@ -161,7 +159,7 @@ macro_rules! declare_name { macro_rules! declare_program( ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); - $crate::declare_name!($name, $name, id); + $crate::declare_name!($name); #[no_mangle] pub extern "C" fn $name( @@ -176,16 +174,12 @@ macro_rules! declare_program( /// Same as declare_program but for native loaders #[macro_export] -macro_rules! declare_loader { - ($bs58_string:expr, $name:ident, $entrypoint:expr) => { - $crate::declare_loader!($bs58_string, $name, $entrypoint, $name, id); - }; - ($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident) => { - $crate::declare_loader!($bs58_string, $name, $entrypoint, $filename, id); - }; - ($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident, $id:path) => { +macro_rules! declare_loader( + ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); - $crate::declare_name!($name, $filename, $id); + $crate::declare_name!($name); + + #[no_mangle] pub extern "C" fn $name( @@ -196,8 +190,8 @@ macro_rules! declare_loader { ) -> Result<(), $crate::instruction::InstructionError> { $entrypoint(program_id, keyed_accounts, instruction_data, invoke_context) } - }; -} + ) +); pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 68d791710b..cdc28eb5f3 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -6,7 +6,6 @@ extern crate self as solana_sdk; pub mod account; pub mod account_utils; pub mod bpf_loader; -pub mod bpf_loader_deprecated; pub mod clock; pub mod commitment_config; pub mod decode_error;