Skip to content

Commit e058e93

Browse files
committed
Fix instruction data validation
1 parent 5291729 commit e058e93

File tree

2 files changed

+44
-86
lines changed

2 files changed

+44
-86
lines changed

p-token/src/processor/set_authority.rs

Lines changed: 22 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,22 @@ use super::validate_owner;
1313
pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
1414
// Validates the instruction data.
1515

16-
let args = SetAuthority::try_from_bytes(instruction_data)?;
16+
// SAFETY: The expected size of the instruction data is either 2 or 34 bytes:
17+
// - authority_type (1 byte)
18+
// - option + new_authority (1 byte + 32 bytes)
19+
let (authority_type, new_authority) = unsafe {
20+
match instruction_data.len() {
21+
2 if *instruction_data.get_unchecked(1) == 0 => (
22+
AuthorityType::try_from(*instruction_data.get_unchecked(0))?,
23+
None,
24+
),
25+
34 if *instruction_data.get_unchecked(1) == 1 => (
26+
AuthorityType::try_from(*instruction_data.get_unchecked(0))?,
27+
Some(&*(instruction_data.as_ptr().add(2) as *const Pubkey)),
28+
),
29+
_ => return Err(ProgramError::InvalidInstructionData),
30+
}
31+
};
1732

1833
// Validates the accounts.
1934

@@ -30,11 +45,11 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
3045
return Err(TokenError::AccountFrozen.into());
3146
}
3247

33-
match args.authority_type()? {
48+
match authority_type {
3449
AuthorityType::AccountOwner => {
3550
validate_owner(&account.owner, authority_info, remaining)?;
3651

37-
if let Some(authority) = args.new_authority() {
52+
if let Some(authority) = new_authority {
3853
account.owner = *authority;
3954
} else {
4055
return Err(TokenError::InvalidInstruction.into());
@@ -51,7 +66,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
5166
let authority = account.close_authority().unwrap_or(&account.owner);
5267
validate_owner(authority, authority_info, remaining)?;
5368

54-
if let Some(authority) = args.new_authority() {
69+
if let Some(authority) = new_authority {
5570
account.set_close_authority(authority);
5671
} else {
5772
account.clear_close_authority();
@@ -66,15 +81,15 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
6681
// `load_mut` validates that the mint is initialized.
6782
let mint = unsafe { load_mut::<Mint>(account_info.borrow_mut_data_unchecked())? };
6883

69-
match args.authority_type()? {
84+
match authority_type {
7085
AuthorityType::MintTokens => {
7186
// Once a mint's supply is fixed, it cannot be undone by setting a new
7287
// mint_authority.
7388
let mint_authority = mint.mint_authority().ok_or(TokenError::FixedSupply)?;
7489

7590
validate_owner(mint_authority, authority_info, remaining)?;
7691

77-
if let Some(authority) = args.new_authority() {
92+
if let Some(authority) = new_authority {
7893
mint.set_mint_authority(authority);
7994
} else {
8095
mint.clear_mint_authority();
@@ -89,7 +104,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
89104

90105
validate_owner(freeze_authority, authority_info, remaining)?;
91106

92-
if let Some(authority) = args.new_authority() {
107+
if let Some(authority) = new_authority {
93108
mint.set_freeze_authority(authority);
94109
} else {
95110
mint.clear_freeze_authority();
@@ -105,40 +120,3 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
105120

106121
Ok(())
107122
}
108-
109-
#[repr(C)]
110-
struct SetAuthority {
111-
authority_type: u8,
112-
113-
new_authority: (u8, Pubkey),
114-
}
115-
116-
impl SetAuthority {
117-
#[inline]
118-
pub fn try_from_bytes(bytes: &[u8]) -> Result<&SetAuthority, ProgramError> {
119-
// The minimum expected size of the instruction data is either 2 or 34 bytes:
120-
// - authority_type (1 byte)
121-
// - option + new_authority (1 byte + 32 bytes)
122-
unsafe {
123-
match bytes.len() {
124-
2 if *bytes.get_unchecked(1) == 0 => Ok(&*(bytes.as_ptr() as *const SetAuthority)),
125-
34 => Ok(&*(bytes.as_ptr() as *const SetAuthority)),
126-
_ => Err(ProgramError::InvalidInstructionData),
127-
}
128-
}
129-
}
130-
131-
#[inline]
132-
pub fn authority_type(&self) -> Result<AuthorityType, ProgramError> {
133-
self.authority_type.try_into()
134-
}
135-
136-
#[inline]
137-
pub fn new_authority(&self) -> Option<&Pubkey> {
138-
if self.new_authority.0 == 0 {
139-
Option::None
140-
} else {
141-
Option::Some(&self.new_authority.1)
142-
}
143-
}
144-
}

p-token/src/processor/shared/initialize_mint.rs

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,25 @@ pub fn process_initialize_mint(
1919
) -> ProgramResult {
2020
// Validates the instruction data.
2121

22-
let args = InitializeMint::try_from_bytes(instruction_data)?;
22+
// SAFETY: The minimum size of the instruction data is either 34 or 66 bytes:
23+
// - decimals (1 byte)
24+
// - mint_authority (32 bytes)
25+
// - option + freeze_authority (1 byte + 32 bytes)
26+
let (decimals, mint_authority, freeze_authority) = unsafe {
27+
match instruction_data.len() {
28+
34 if *instruction_data.get_unchecked(33) == 0 => (
29+
*instruction_data.get_unchecked(0),
30+
&*(instruction_data.as_ptr().add(1) as *const Pubkey),
31+
None,
32+
),
33+
66 if *instruction_data.get_unchecked(33) == 1 => (
34+
*instruction_data.get_unchecked(0),
35+
&*(instruction_data.as_ptr().add(1) as *const Pubkey),
36+
Some(&*(instruction_data.as_ptr().add(34) as *const Pubkey)),
37+
),
38+
_ => return Err(ProgramError::InvalidInstructionData),
39+
}
40+
};
2341

2442
// Validates the accounts.
2543

@@ -60,50 +78,12 @@ pub fn process_initialize_mint(
6078
// Initialize the mint.
6179

6280
mint.set_initialized();
63-
mint.set_mint_authority(&args.mint_authority);
64-
mint.decimals = args.decimals;
81+
mint.set_mint_authority(mint_authority);
82+
mint.decimals = decimals;
6583

66-
if let Some(freeze_authority) = args.freeze_authority() {
84+
if let Some(freeze_authority) = freeze_authority {
6785
mint.set_freeze_authority(freeze_authority);
6886
}
6987

7088
Ok(())
7189
}
72-
73-
/// Instruction data for the `InitializeMint` instruction.
74-
#[repr(C)]
75-
struct InitializeMint {
76-
pub(crate) decimals: u8,
77-
78-
pub(crate) mint_authority: Pubkey,
79-
80-
freeze_authority: (u8, Pubkey),
81-
}
82-
83-
impl InitializeMint {
84-
#[inline]
85-
pub fn try_from_bytes(bytes: &[u8]) -> Result<&InitializeMint, ProgramError> {
86-
// The minimum expected size of the instruction data is either 34 or 66 bytes:
87-
// - decimals (1 byte)
88-
// - mint_authority (32 bytes)
89-
// - option + freeze_authority (1 byte + 32 bytes)
90-
unsafe {
91-
match bytes.len() {
92-
34 if *bytes.get_unchecked(33) == 0 => {
93-
Ok(&*(bytes.as_ptr() as *const InitializeMint))
94-
}
95-
66 => Ok(&*(bytes.as_ptr() as *const InitializeMint)),
96-
_ => Err(ProgramError::InvalidInstructionData),
97-
}
98-
}
99-
}
100-
101-
#[inline]
102-
pub fn freeze_authority(&self) -> Option<&Pubkey> {
103-
if self.freeze_authority.0 == 0 {
104-
Option::None
105-
} else {
106-
Option::Some(&self.freeze_authority.1)
107-
}
108-
}
109-
}

0 commit comments

Comments
 (0)