فهرست منبع

v3.0: Fix - Restrict address space of sysvar syscalls in SIMD-0219 (backport of #7832) (#7959)

* Fix - Restrict address space of sysvar syscalls in SIMD-0219 (#7832)

* Restrict address space of sysvar syscalls as well (similar to CPI).

* Adds a test for the new restriction.

* Rekeys stricter_abi_and_runtime_constraints.
mergify[bot] 2 ماه پیش
والد
کامیت
01781bb975
4فایلهای تغییر یافته به همراه52 افزوده شده و 5 حذف شده
  1. 2 2
      feature-set/src/lib.rs
  2. 10 0
      programs/sbf/rust/sysvar/src/lib.rs
  3. 24 2
      programs/sbf/tests/sysvar.rs
  4. 16 1
      syscalls/src/sysvar.rs

+ 2 - 2
feature-set/src/lib.rs

@@ -751,7 +751,7 @@ pub mod apply_cost_tracker_during_replay {
 }
 
 pub mod stricter_abi_and_runtime_constraints {
-    solana_pubkey::declare_id!("C37iaPi6VE4CZDueU1vL8y6pGp5i8amAbEsF31xzz723");
+    solana_pubkey::declare_id!("CxeBn9PVeeXbmjbNwLv6U4C6svNxnC4JX6mfkvgeMocM");
 }
 
 pub mod add_set_tx_loaded_accounts_data_size_instruction {
@@ -1277,7 +1277,7 @@ pub static FEATURE_NAMES: LazyLock<AHashMap<Pubkey, &'static str>> = LazyLock::n
         (clean_up_delegation_errors::id(), "Return InsufficientDelegation instead of InsufficientFunds or InsufficientStake where applicable #31206"),
         (vote_state_add_vote_latency::id(), "replace Lockout with LandedVote (including vote latency) in vote state #31264"),
         (checked_arithmetic_in_fee_validation::id(), "checked arithmetic in fee validation #31273"),
-        (stricter_abi_and_runtime_constraints::id(), "use memory regions to map account data into the rbpf vm instead of copying the data"),
+        (stricter_abi_and_runtime_constraints::id(), "SIMD-0219: Stricter ABI and Runtime Constraints"),
         (last_restart_slot_sysvar::id(), "enable new sysvar last_restart_slot"),
         (reduce_stake_warmup_cooldown::id(), "reduce stake warmup cooldown from 25% to 9%"),
         (revise_turbine_epoch_stakes::id(), "revise turbine epoch stakes"),

+ 10 - 0
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),
     }
 }

+ 24 - 2
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());
 }

+ 16 - 1
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<T: std::fmt::Debug + SysvarSerialize + Clone>(
@@ -17,6 +17,14 @@ fn get_sysvar<T: std::fmt::Debug + SysvarSerialize + Clone>(
             .sysvar_base_cost
             .saturating_add(size_of::<T>() 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,