Browse Source

Add fuzzing feature

febo 5 months ago
parent
commit
e976c43d8e

+ 4 - 0
interface/Cargo.toml

@@ -11,6 +11,10 @@ readme = "./README.md"
 [lib]
 crate-type = ["rlib"]
 
+[features]
+default = ["fuzzing"]
+fuzzing = []
+
 [dependencies]
 pinocchio = "0.8.4"
 pinocchio-pubkey = "0.2"

+ 17 - 2
interface/src/state/account.rs

@@ -1,5 +1,5 @@
 use {
-    super::{account_state::AccountState, COption, Initializable, Transmutable},
+    super::{account_state::AccountState, validate_option, COption, Initializable, Transmutable},
     pinocchio::{program_error::ProgramError, pubkey::Pubkey},
 };
 
@@ -158,6 +158,21 @@ impl Transmutable for Account {
 impl Initializable for Account {
     #[inline(always)]
     fn is_initialized(&self) -> Result<bool, ProgramError> {
-        AccountState::try_from(self.state).map(|state| state != AccountState::Uninitialized)
+        #[cfg(feature = "fuzzing")]
+        // delegate
+        validate_option(self.delegate.0)?;
+
+        // state
+        let state = AccountState::try_from(self.state)?;
+
+        #[cfg(feature = "fuzzing")]
+        // is_native
+        validate_option(self.is_native)?;
+
+        #[cfg(feature = "fuzzing")]
+        // close authority
+        validate_option(self.close_authority.0)?;
+
+        Ok(state != AccountState::Uninitialized)
     }
 }

+ 17 - 6
interface/src/state/mint.rs

@@ -1,5 +1,5 @@
 use {
-    super::{COption, Initializable, Transmutable},
+    super::{validate_option, COption, Initializable, Transmutable},
     pinocchio::{program_error::ProgramError, pubkey::Pubkey},
 };
 
@@ -92,10 +92,21 @@ impl Transmutable for Mint {
 impl Initializable for Mint {
     #[inline(always)]
     fn is_initialized(&self) -> Result<bool, ProgramError> {
-        match self.is_initialized {
-            0 => Ok(false),
-            1 => Ok(true),
-            _ => Err(ProgramError::InvalidAccountData),
-        }
+        #[cfg(feature = "fuzzing")]
+        // mint_authority
+        validate_option(self.mint_authority.0)?;
+
+        // is_initialized
+        let initialized = match self.is_initialized {
+            0 => false,
+            1 => true,
+            _ => return Err(ProgramError::InvalidAccountData),
+        };
+
+        #[cfg(feature = "fuzzing")]
+        // freeze_authority
+        validate_option(self.freeze_authority.0)?;
+
+        Ok(initialized)
     }
 }

+ 12 - 1
interface/src/state/mod.rs

@@ -1,4 +1,4 @@
-use pinocchio::program_error::ProgramError;
+use pinocchio::{program_error::ProgramError, ProgramResult};
 
 pub mod account;
 pub mod account_state;
@@ -93,3 +93,14 @@ pub unsafe fn load_mut_unchecked<T: Transmutable>(
     }
     Ok(&mut *(bytes.as_mut_ptr() as *mut T))
 }
+
+#[cfg(feature = "fuzzing")]
+/// Validates a `COption` mask value.
+#[inline(always)]
+const fn validate_option(value: [u8; 4]) -> ProgramResult {
+    if u32::from_le_bytes(value) > 1 {
+        Err(ProgramError::InvalidAccountData)
+    } else {
+        Ok(())
+    }
+}

+ 2 - 0
p-token/Cargo.toml

@@ -12,7 +12,9 @@ readme = "./README.md"
 crate-type = ["cdylib"]
 
 [features]
+default = ["fuzzing"]
 logging = []
+fuzzing = []
 
 [dependencies]
 pinocchio = "0.8.4"

+ 8 - 1
p-token/src/entrypoint.rs

@@ -35,10 +35,13 @@ pub fn process_instruction(
     accounts: &[AccountInfo],
     instruction_data: &[u8],
 ) -> ProgramResult {
-    let [discriminator, remaining @ ..] = instruction_data else {
+    #[cfg(not(feature = "fuzzing"))]
+    let [discriminator, remaining @ ..] = instruction_data
+    else {
         return Err(TokenError::InvalidInstruction.into());
     };
 
+    #[cfg(not(feature = "fuzzing"))]
     let result = if *discriminator == 255 {
         // 255 - Batch
         #[cfg(feature = "logging")]
@@ -49,6 +52,9 @@ pub fn process_instruction(
         inner_process_instruction(accounts, instruction_data)
     };
 
+    #[cfg(feature = "fuzzing")]
+    let result = inner_process_instruction(accounts, instruction_data);
+
     result.inspect_err(log_error)
 }
 
@@ -273,6 +279,7 @@ fn inner_process_remaining_instruction(
 
             process_ui_amount_to_amount(accounts, instruction_data)
         }
+        #[cfg(not(feature = "fuzzing"))]
         // 38 - WithdrawExcessLamports
         38 => {
             #[cfg(feature = "logging")]

+ 6 - 2
p-token/src/processor/mod.rs

@@ -18,6 +18,7 @@ use {
 pub mod amount_to_ui_amount;
 pub mod approve;
 pub mod approve_checked;
+#[cfg(not(feature = "fuzzing"))]
 pub mod batch;
 pub mod burn;
 pub mod burn_checked;
@@ -41,13 +42,17 @@ pub mod thaw_account;
 pub mod transfer;
 pub mod transfer_checked;
 pub mod ui_amount_to_amount;
+#[cfg(not(feature = "fuzzing"))]
 pub mod withdraw_excess_lamports;
 // Shared processors.
 pub mod shared;
 
+#[cfg(not(feature = "fuzzing"))]
+pub use {batch::process_batch, withdraw_excess_lamports::process_withdraw_excess_lamports};
+
 pub use {
     amount_to_ui_amount::process_amount_to_ui_amount, approve::process_approve,
-    approve_checked::process_approve_checked, batch::process_batch, burn::process_burn,
+    approve_checked::process_approve_checked, burn::process_burn,
     burn_checked::process_burn_checked, close_account::process_close_account,
     freeze_account::process_freeze_account, get_account_data_size::process_get_account_data_size,
     initialize_account::process_initialize_account,
@@ -61,7 +66,6 @@ pub use {
     set_authority::process_set_authority, sync_native::process_sync_native,
     thaw_account::process_thaw_account, transfer::process_transfer,
     transfer_checked::process_transfer_checked, ui_amount_to_amount::process_ui_amount_to_amount,
-    withdraw_excess_lamports::process_withdraw_excess_lamports,
 };
 
 /// Number of bytes in a `u64`.

+ 2 - 0
p-token/tests/batch.rs

@@ -1,3 +1,5 @@
+#![cfg(not(feature = "fuzzing"))]
+
 mod setup;
 
 use {

+ 1 - 0
p-token/tests/withdraw_excess_lamports.rs

@@ -1,3 +1,4 @@
+#![cfg(not(feature = "fuzzing"))]
 #![allow(clippy::arithmetic_side_effects)]
 
 mod setup;