diff --git a/programs/sbf/rust/sysvar/src/lib.rs b/programs/sbf/rust/sysvar/src/lib.rs index b9186a6ce8f..1994cdff6a1 100644 --- a/programs/sbf/rust/sysvar/src/lib.rs +++ b/programs/sbf/rust/sysvar/src/lib.rs @@ -209,6 +209,16 @@ pub fn process_instruction( Ok(()) } + Some(&4) => { + // Attempt to store the result in the input region instead of the stack or heap + unsafe { + solana_define_syscall::definitions::sol_get_epoch_rewards_sysvar( + accounts[2].data.borrow_mut().as_mut_ptr(), + ) + }; + + Ok(()) + } _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/programs/sbf/tests/sysvar.rs b/programs/sbf/tests/sysvar.rs index bb95a08ca99..6728e259949 100644 --- a/programs/sbf/tests/sysvar.rs +++ b/programs/sbf/tests/sysvar.rs @@ -69,7 +69,13 @@ fn test_sysvar_syscalls() { &authority_keypair, "solana_sbf_rust_sysvar", ); + let dummy_account_key = Pubkey::new_unique(); + bank.store_account( + &dummy_account_key, + &solana_account::AccountSharedData::new(1, 32, &program_id), + ); bank.freeze(); + let blockhash = bank.last_blockhash(); for ix_discriminator in 0..4 { let instruction = Instruction::new_with_bincode( @@ -77,7 +83,7 @@ fn test_sysvar_syscalls() { &[ix_discriminator], vec![ AccountMeta::new(mint_keypair.pubkey(), true), - AccountMeta::new(Pubkey::new_unique(), false), + AccountMeta::new(dummy_account_key, false), AccountMeta::new_readonly(clock::id(), false), AccountMeta::new_readonly(epoch_schedule::id(), false), AccountMeta::new_readonly(instructions::id(), false), @@ -90,11 +96,27 @@ fn test_sysvar_syscalls() { AccountMeta::new_readonly(epoch_rewards::id(), false), ], ); - let blockhash = bank.last_blockhash(); let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); let transaction = Transaction::new(&[&mint_keypair], message, blockhash); let sanitized_tx = RuntimeTransaction::from_transaction_for_tests(transaction); let result = bank.simulate_transaction(&sanitized_tx, false); assert!(result.result.is_ok()); } + + // Storing the result of get_sysvar() in the input region is not allowed + // because of the 16 byte alignment requirement of the EpochRewards sysvar. + let instruction = Instruction::new_with_bincode( + program_id, + &[4], + vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new_readonly(epoch_rewards::id(), false), + AccountMeta::new(dummy_account_key, false), + ], + ); + let message = Message::new(&[instruction], Some(&mint_keypair.pubkey())); + let transaction = Transaction::new(&[&mint_keypair], message, blockhash); + let sanitized_tx = RuntimeTransaction::from_transaction_for_tests(transaction); + let result = bank.simulate_transaction(&sanitized_tx, false); + assert!(result.result.is_err()); } diff --git a/syscalls/src/sysvar.rs b/syscalls/src/sysvar.rs index a692b881307..17c03b9006f 100644 --- a/syscalls/src/sysvar.rs +++ b/syscalls/src/sysvar.rs @@ -1,6 +1,6 @@ use { super::*, crate::translate_mut, - solana_program_runtime::execution_budget::SVMTransactionExecutionCost, + solana_program_runtime::execution_budget::SVMTransactionExecutionCost, solana_sbpf::ebpf, }; fn get_sysvar( @@ -17,6 +17,14 @@ fn get_sysvar( .sysvar_base_cost .saturating_add(size_of::() as u64), )?; + + if var_addr >= ebpf::MM_INPUT_START + && invoke_context + .get_feature_set() + .stricter_abi_and_runtime_constraints + { + return Err(SyscallError::InvalidPointer.into()); + } translate_mut!( memory_mapping, check_aligned, @@ -203,6 +211,13 @@ declare_builtin_function!( .saturating_add(std::cmp::max(sysvar_buf_cost, mem_op_base_cost)), )?; + if var_addr >= ebpf::MM_INPUT_START + && invoke_context + .get_feature_set() + .stricter_abi_and_runtime_constraints + { + return Err(SyscallError::InvalidPointer.into()); + } // Abort: "Not all bytes in VM memory range `[var_addr, var_addr + length)` are writable." translate_mut!( memory_mapping,