From 7e600bd4510324e9fb08c5f2294cf8dae123135b Mon Sep 17 00:00:00 2001 From: Ben Newhouse Date: Tue, 16 Nov 2021 10:02:22 -0500 Subject: [PATCH] Fix BPF parameter alignment to work regardless of target ABI (#21271) --- .../developing/on-chain-programs/overview.md | 29 +++++++++---------- programs/bpf_loader/src/serialization.rs | 4 +-- sdk/program/src/entrypoint.rs | 7 +++-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/src/developing/on-chain-programs/overview.md b/docs/src/developing/on-chain-programs/overview.md index e9cd7bd615..5c22542a33 100644 --- a/docs/src/developing/on-chain-programs/overview.md +++ b/docs/src/developing/on-chain-programs/overview.md @@ -199,21 +199,20 @@ encoding is little endian): - 1 byte indicating if this is a duplicate account, if not a duplicate then the value is 0xff, otherwise the value is the index of the account it is a duplicate of. - - 7 bytes of padding - - if not duplicate - - 1 byte padding - - 1 byte boolean, true if account is a signer - - 1 byte boolean, true if account is writable - - 1 byte boolean, true if account is executable - - 4 bytes of padding - - 32 bytes of the account public key - - 32 bytes of the account's owner public key - - 8 byte unsigned number of lamports owned by the account - - 8 bytes unsigned number of bytes of account data - - x bytes of account data - - 10k bytes of padding, used for realloc - - enough padding to align the offset to 8 bytes. - - 8 bytes rent epoch + - If duplicate: 7 bytes of padding + - If not duplicate: + - 1 byte boolean, true if account is a signer + - 1 byte boolean, true if account is writable + - 1 byte boolean, true if account is executable + - 4 bytes of padding + - 32 bytes of the account public key + - 32 bytes of the account's owner public key + - 8 byte unsigned number of lamports owned by the account + - 8 bytes unsigned number of bytes of account data + - x bytes of account data + - 10k bytes of padding, used for realloc + - enough padding to align the offset to 8 bytes. + - 8 bytes rent epoch - 8 bytes of unsigned number of instruction data - x bytes of instruction data - 32 bytes of the program id diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 2eadd33adf..cf994d132d 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -3,7 +3,7 @@ use solana_rbpf::{aligned_memory::AlignedMemory, ebpf::HOST_ALIGN}; use solana_sdk::{ account::{ReadableAccount, WritableAccount}, bpf_loader_deprecated, - entrypoint::MAX_PERMITTED_DATA_INCREASE, + entrypoint::{MAX_PERMITTED_DATA_INCREASE, PARAMETER_ALIGNMENT}, instruction::InstructionError, keyed_account::KeyedAccount, pubkey::Pubkey, @@ -242,7 +242,7 @@ pub fn serialize_parameters_aligned( .map_err(|_| InstructionError::InvalidArgument)?; v.resize( MAX_PERMITTED_DATA_INCREASE - + (v.write_index() as *const u8).align_offset(align_of::()), + + (v.write_index() as *const u8).align_offset(PARAMETER_ALIGNMENT), 0, ) .map_err(|_| InstructionError::InvalidArgument)?; diff --git a/sdk/program/src/entrypoint.rs b/sdk/program/src/entrypoint.rs index b9fade524d..317f0665fe 100644 --- a/sdk/program/src/entrypoint.rs +++ b/sdk/program/src/entrypoint.rs @@ -7,7 +7,7 @@ use alloc::vec::Vec; use std::{ alloc::Layout, cell::RefCell, - mem::{align_of, size_of}, + mem::size_of, ptr::null_mut, rc::Rc, // Hide Result from bindgen gets confused about generics in non-generic type declarations @@ -252,6 +252,9 @@ unsafe impl std::alloc::GlobalAlloc for BumpAllocator { /// Maximum number of bytes a program may add to an account during a single realloc pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10; +// Parameters passed to the entrypoint input buffer are aligned on 8-byte boundaries +pub const PARAMETER_ALIGNMENT: usize = 8; + /// Deserialize the input arguments /// /// The integer arithmetic in this method is safe when called on a buffer that was @@ -309,7 +312,7 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec()); // padding + offset += (offset as *const u8).align_offset(PARAMETER_ALIGNMENT); // padding #[allow(clippy::cast_ptr_alignment)] let rent_epoch = *(input.add(offset) as *const u64);