From dbc58455df8564ffba98d99d3e4902a93f44cb70 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 27 Apr 2021 23:01:43 +0000 Subject: [PATCH] Retain alloc'd and updated data in cpi (backport #16850) (#16890) * Retain alloc'd and updated data in cpi (#16850) (cherry picked from commit 9b3a59f0302ed324336aba7d0796913260aa0953) # Conflicts: # programs/bpf_loader/src/syscalls.rs # sdk/src/feature_set.rs * resolve conflicts Co-authored-by: Jack May --- programs/bpf/rust/invoke/src/lib.rs | 26 +++++++++++ programs/bpf/rust/invoked/src/instruction.rs | 1 + programs/bpf/rust/invoked/src/processor.rs | 49 +++++++++++++++++++- programs/bpf/tests/programs.rs | 2 + programs/bpf_loader/src/syscalls.rs | 26 +++++++---- sdk/src/feature_set.rs | 5 ++ 6 files changed, 100 insertions(+), 9 deletions(-) diff --git a/programs/bpf/rust/invoke/src/lib.rs b/programs/bpf/rust/invoke/src/lib.rs index 330fc1d5fb..e0889766ee 100644 --- a/programs/bpf/rust/invoke/src/lib.rs +++ b/programs/bpf/rust/invoke/src/lib.rs @@ -374,6 +374,32 @@ fn process_instruction( accounts[INVOKED_ARGUMENT_INDEX].data.borrow_mut()[..NUM_BYTES] ); } + + msg!("Create account and init data"); + { + let from_lamports = accounts[FROM_INDEX].lamports(); + let to_lamports = accounts[DERIVED_KEY2_INDEX].lamports(); + + let instruction = create_instruction( + *accounts[INVOKED_PROGRAM_INDEX].key, + &[ + (accounts[FROM_INDEX].key, true, true), + (accounts[DERIVED_KEY2_INDEX].key, true, false), + (accounts[SYSTEM_PROGRAM_INDEX].key, false, false), + ], + vec![CREATE_AND_INIT, bump_seed2], + ); + invoke(&instruction, accounts)?; + + assert_eq!(accounts[FROM_INDEX].lamports(), from_lamports - 1); + assert_eq!(accounts[DERIVED_KEY2_INDEX].lamports(), to_lamports + 1); + let data = accounts[DERIVED_KEY2_INDEX].try_borrow_mut_data()?; + assert_eq!(data[0], 0x0e); + assert_eq!(data[MAX_PERMITTED_DATA_INCREASE - 1], 0x0f); + for i in 1..20 { + assert_eq!(data[i], i as u8); + } + } } TEST_PRIVILEGE_ESCALATION_SIGNER => { msg!("Test privilege escalation signer"); diff --git a/programs/bpf/rust/invoked/src/instruction.rs b/programs/bpf/rust/invoked/src/instruction.rs index 770ea08619..a6c16dc8cc 100644 --- a/programs/bpf/rust/invoked/src/instruction.rs +++ b/programs/bpf/rust/invoked/src/instruction.rs @@ -17,6 +17,7 @@ pub const VERIFY_PRIVILEGE_DEESCALATION: u8 = 8; pub const VERIFY_PRIVILEGE_DEESCALATION_ESCALATION_SIGNER: u8 = 9; pub const VERIFY_PRIVILEGE_DEESCALATION_ESCALATION_WRITABLE: u8 = 10; pub const WRITE_ACCOUNT: u8 = 11; +pub const CREATE_AND_INIT: u8 = 12; pub fn create_instruction( program_id: Pubkey, diff --git a/programs/bpf/rust/invoked/src/processor.rs b/programs/bpf/rust/invoked/src/processor.rs index 1c9c8c4948..062ca26c56 100644 --- a/programs/bpf/rust/invoked/src/processor.rs +++ b/programs/bpf/rust/invoked/src/processor.rs @@ -6,11 +6,12 @@ use crate::instruction::*; use solana_program::{ account_info::AccountInfo, bpf_loader, entrypoint, - entrypoint::ProgramResult, + entrypoint::{ProgramResult, MAX_PERMITTED_DATA_INCREASE}, msg, program::{invoke, invoke_signed}, program_error::ProgramError, pubkey::Pubkey, + system_instruction, }; entrypoint!(process_instruction); @@ -236,6 +237,52 @@ fn process_instruction( accounts[ARGUMENT_INDEX].data.borrow_mut()[i as usize] = instruction_data[1]; } } + CREATE_AND_INIT => { + msg!("Create and init data"); + { + const FROM_INDEX: usize = 0; + const DERIVED_KEY2_INDEX: usize = 1; + + let from_lamports = accounts[FROM_INDEX].lamports(); + let to_lamports = accounts[DERIVED_KEY2_INDEX].lamports(); + assert_eq!(accounts[DERIVED_KEY2_INDEX].data_len(), 0); + assert!(solana_program::system_program::check_id( + accounts[DERIVED_KEY2_INDEX].owner + )); + + let bump_seed2 = instruction_data[1]; + let instruction = system_instruction::create_account( + accounts[FROM_INDEX].key, + accounts[DERIVED_KEY2_INDEX].key, + 1, + MAX_PERMITTED_DATA_INCREASE as u64, + program_id, + ); + invoke_signed( + &instruction, + accounts, + &[&[b"Lil'", b"Bits", &[bump_seed2]]], + )?; + + assert_eq!(accounts[FROM_INDEX].lamports(), from_lamports - 1); + assert_eq!(accounts[DERIVED_KEY2_INDEX].lamports(), to_lamports + 1); + assert_eq!(program_id, accounts[DERIVED_KEY2_INDEX].owner); + assert_eq!( + accounts[DERIVED_KEY2_INDEX].data_len(), + MAX_PERMITTED_DATA_INCREASE + ); + let mut data = accounts[DERIVED_KEY2_INDEX].try_borrow_mut_data()?; + assert_eq!(data[0], 0); + data[0] = 0x0e; + assert_eq!(data[0], 0x0e); + assert_eq!(data[MAX_PERMITTED_DATA_INCREASE - 1], 0); + data[MAX_PERMITTED_DATA_INCREASE - 1] = 0x0f; + assert_eq!(data[MAX_PERMITTED_DATA_INCREASE - 1], 0x0f); + for i in 1..20 { + data[i] = i as u8; + } + } + } _ => panic!(), } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 0060aff773..a4f60fb8a0 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -884,6 +884,8 @@ fn test_program_bpf_invoke_sanity() { invoked_program_id.clone(), invoked_program_id.clone(), invoked_program_id.clone(), + invoked_program_id.clone(), + solana_sdk::system_program::id(), ], }; assert_eq!(invoked_programs.len(), expected_invoked_programs.len()); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index a0e67642b6..f855381898 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -20,7 +20,7 @@ use solana_sdk::{ epoch_schedule::EpochSchedule, feature_set::{ cpi_data_cost, cpi_share_ro_and_exec_accounts, demote_sysvar_write_locks, - enforce_aligned_host_addrs, sysvar_via_syscall, + enforce_aligned_host_addrs, sysvar_via_syscall, update_data_on_realloc, }, hash::{Hasher, HASH_BYTES}, ic_msg, @@ -1997,7 +1997,7 @@ fn call<'a>( let invoke_context = syscall.get_context()?; for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() { let account = account.borrow(); - if let Some(account_ref) = account_ref { + if let Some(mut account_ref) = account_ref { if message.is_writable(i, demote_sysvar_write_locks) && !account.executable { *account_ref.lamports = account.lamports; *account_ref.owner = account.owner; @@ -2027,12 +2027,22 @@ fn call<'a>( ) .into()); } - let _ = translate( - memory_mapping, - AccessType::Store, - account_ref.vm_data_addr, - account.data().len() as u64, - )?; + if invoke_context.is_feature_active(&update_data_on_realloc::id()) { + account_ref.data = translate_slice_mut::( + memory_mapping, + account_ref.vm_data_addr, + account.data().len() as u64, + &bpf_loader_deprecated::id(), // Don't care since it is byte aligned + true, + )?; + } else { + let _ = translate( + memory_mapping, + AccessType::Store, + account_ref.vm_data_addr, + account.data().len() as u64, + )?; + } *account_ref.ref_to_len_in_vm = account.data().len() as u64; *account_ref.serialized_len_ptr = account.data().len() as u64; } diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 54b8da042f..f10f4b10f5 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -127,6 +127,10 @@ pub mod enforce_aligned_host_addrs { solana_sdk::declare_id!("6Qob9Z4RwGdf599FDVCqsjuKjR8ZFR3oVs2ByRLWBsua"); } +pub mod update_data_on_realloc { + solana_sdk::declare_id!("BkPcYCrwHXBoTsv9vMhiRF9gteZmDj3Uwisz9CDjoMKp"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -159,6 +163,7 @@ lazy_static! { (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"), + (update_data_on_realloc::id(), "Retain updated data values modified after realloc via CPI"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()