Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A close macro implementation for AccountInfo #42

Merged
merged 5 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions sdk/pinocchio/src/account_info.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Data structures to represent account information.

use core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull, slice::from_raw_parts_mut};

use crate::{program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memset_};
use crate::{program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memset_, ProgramResult};

/// Maximum number of bytes a program may add to an account during a
/// single realloc.
Expand Down Expand Up @@ -379,6 +378,54 @@ impl AccountInfo {
Ok(())
}

/// Zero out the the account's data_len, lamports and owner fields, effectively
L0STE marked this conversation as resolved.
Show resolved Hide resolved
/// closing the account.
///
/// This doesn't protect against future reinitialization of the account
/// since the account_data will need to be zeroed out as well. Or if the attacker
/// has access to the keypair of the account that we're trying to close, they can
/// just add the lenght, lamports and owner back before the data is wiped out from
/// the ledger.
///
/// This works because the 48 bytes before the account data are:
/// - 8 bytes for the data_len
/// - 8 bytes for the lamports
/// - 32 bytes for the owner
pub fn close(&self) -> ProgramResult {
{
let _ = self.try_borrow_mut_data()?;
}

unsafe {
self.close_unchecked();
}

Ok(())
}
///
/// # Safety
///
/// This method makes assumptions about the layout and location of memory
/// referenced by `AccountInfo` fields. It should only be called for
/// instances of `AccountInfo` that were created by the runtime and received
/// in the `process_instruction` entrypoint of a program.
///
/// This method is unsafe because it does not check if the account data is already
/// borrowed. It should only be called when the account is not being used.
#[inline(always)]
pub unsafe fn close_unchecked(&self) {
// Zero out the account owner. While the field is a `Pubkey`, it is quicker
// to zero the 32 bytes as 4 x `u64`s.
*(self.data_ptr().sub(48) as *mut u64) = 0u64;
*(self.data_ptr().sub(40) as *mut u64) = 0u64;
*(self.data_ptr().sub(32) as *mut u64) = 0u64;
*(self.data_ptr().sub(16) as *mut u64) = 0u64;
// Zero the account lamports.
(*self.raw).lamports = 0;
// Zero the account data length.
(*self.raw).data_len = 0;
}

/// Returns the memory address of the account data.
fn data_ptr(&self) -> *mut u8 {
unsafe { (self.raw as *const _ as *mut u8).add(core::mem::size_of::<Account>()) }
Expand Down
1 change: 1 addition & 0 deletions sdk/pinocchio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! [`solana-program`]: https://docs.rs/solana-program/latest/solana_program/

#![no_std]
#![cfg_attr(target_os = "solana", feature(asm_experimental_arch, asm_const))]

pub mod account_info;
pub mod entrypoint;
Expand Down