Skip to content

Commit 17cbf43

Browse files
authored
Merge pull request #28 from lazor-kit/fix/audit-n1-n2-n3
fix(audit): N1 use auth_bump, N2 validate system_program, N3 check RP…
2 parents de69ded + 50bb5b7 commit 17cbf43

31 files changed

Lines changed: 373 additions & 21998 deletions

program/src/auth/secp256r1/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ impl Authenticator for Secp256r1Authenticator {
6969
// SAFETY: Pointer alignment checked above. size_of correct.
7070
let header = unsafe { &mut *(auth_data.as_mut_ptr() as *mut AuthorityAccountHeader) };
7171

72+
// Compute hash of user-provided RP ID and verify against stored hash (audit N3)
73+
let stored_rp_id_hash = &auth_data[header_size..header_size + 32];
74+
#[allow(unused_assignments)]
75+
let mut computed_rp_id_hash = [0u8; 32];
76+
#[cfg(target_os = "solana")]
77+
unsafe {
78+
let _res = pinocchio::syscalls::sol_sha256(
79+
[rp_id].as_ptr() as *const u8,
80+
1,
81+
computed_rp_id_hash.as_mut_ptr(),
82+
);
83+
}
84+
#[cfg(not(target_os = "solana"))]
85+
{
86+
computed_rp_id_hash = [0u8; 32];
87+
}
88+
if computed_rp_id_hash != stored_rp_id_hash {
89+
return Err(AuthError::InvalidPubkey.into());
90+
}
91+
7292
#[allow(unused_assignments)]
7393
let mut hasher = [0u8; 32];
7494
#[cfg(target_os = "solana")]

program/src/processor/create_session.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ pub fn process(
9797
// Get rent from sysvar (fixes audit issue #5 - hardcoded rent calculations)
9898
let rent = Rent::from_account_info(rent_sysvar)?;
9999

100+
// Validate system_program is the correct System Program (audit N2)
101+
if !assertions::sol_assert_bytes_eq(
102+
system_program.key().as_ref(),
103+
&crate::utils::SYSTEM_PROGRAM_ID,
104+
32,
105+
) {
106+
return Err(ProgramError::IncorrectProgramId);
107+
}
108+
100109
if wallet_pda.owner() != program_id || authorizer_pda.owner() != program_id {
101110
return Err(ProgramError::IllegalOwner);
102111
}

program/src/processor/create_wallet.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use pinocchio::{
44
account_info::AccountInfo,
55
instruction::Seed,
66
program_error::ProgramError,
7-
pubkey::{find_program_address, Pubkey},
7+
pubkey::{create_program_address, find_program_address, Pubkey},
88
sysvars::rent::Rent,
99
ProgramResult,
1010
};
@@ -117,6 +117,15 @@ pub fn process(
117117
// Get rent from sysvar (fixes audit issue #5 - hardcoded rent calculations)
118118
let rent = Rent::from_account_info(rent_sysvar)?;
119119

120+
// Validate system_program is the correct System Program (audit N2)
121+
if !sol_assert_bytes_eq(
122+
system_program.key().as_ref(),
123+
&crate::utils::SYSTEM_PROGRAM_ID,
124+
32,
125+
) {
126+
return Err(ProgramError::IncorrectProgramId);
127+
}
128+
120129
let (wallet_key, wallet_bump) = find_program_address(&[b"wallet", &args.user_seed], program_id);
121130
if !sol_assert_bytes_eq(wallet_pda.key().as_ref(), wallet_key.as_ref(), 32) {
122131
return Err(ProgramError::InvalidSeeds);
@@ -129,8 +138,13 @@ pub fn process(
129138
return Err(ProgramError::InvalidSeeds);
130139
}
131140

132-
let (auth_key, auth_bump) =
133-
find_program_address(&[b"authority", wallet_key.as_ref(), id_seed], program_id);
141+
// Use client-provided auth_bump for efficiency (audit N1)
142+
let auth_bump_arr = [args.auth_bump];
143+
let auth_key = create_program_address(
144+
&[b"authority", wallet_key.as_ref(), id_seed, &auth_bump_arr],
145+
program_id,
146+
)
147+
.map_err(|_| ProgramError::InvalidSeeds)?;
134148
if !sol_assert_bytes_eq(auth_pda.key().as_ref(), auth_key.as_ref(), 32) {
135149
return Err(ProgramError::InvalidSeeds);
136150
}
@@ -187,7 +201,7 @@ pub fn process(
187201
let auth_rent = rent.minimum_balance(auth_space);
188202

189203
// Use secure transfer-allocate-assign pattern to prevent DoS (Issue #4)
190-
let auth_bump_arr = [auth_bump];
204+
let auth_bump_arr = [args.auth_bump];
191205
let auth_seeds = [
192206
Seed::from(b"authority"),
193207
Seed::from(wallet_key.as_ref()),
@@ -211,7 +225,7 @@ pub fn process(
211225
discriminator: AccountDiscriminator::Authority as u8,
212226
authority_type: args.authority_type,
213227
role: 0,
214-
bump: auth_bump,
228+
bump: args.auth_bump,
215229
version: crate::state::CURRENT_ACCOUNT_VERSION,
216230
_padding: [0; 3],
217231
counter: 0,

program/src/processor/manage_authority.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use pinocchio::{
55
instruction::Seed,
66
program_error::ProgramError,
77
pubkey::{find_program_address, Pubkey},
8+
sysvars::rent::Rent,
89
ProgramResult,
910
};
1011

@@ -133,6 +134,19 @@ pub fn process_add_authority(
133134
return Err(ProgramError::IllegalOwner);
134135
}
135136

137+
// Validate system_program is the correct System Program (audit N2)
138+
if !sol_assert_bytes_eq(
139+
system_program.key().as_ref(),
140+
&crate::utils::SYSTEM_PROGRAM_ID,
141+
32,
142+
) {
143+
return Err(ProgramError::IncorrectProgramId);
144+
}
145+
let rent_sysvar_info = account_info_iter
146+
.next()
147+
.ok_or(ProgramError::NotEnoughAccountKeys)?;
148+
let rent = Rent::from_account_info(rent_sysvar_info)?;
149+
136150
// Check removed here, moved to type-specific logic
137151
// if !admin_auth_pda.is_writable() {
138152
// return Err(ProgramError::InvalidAccountData);
@@ -194,11 +208,14 @@ pub fn process_add_authority(
194208
check_zero_data(new_auth_pda, ProgramError::AccountAlreadyInitialized)?;
195209

196210
let header_size = std::mem::size_of::<AuthorityAccountHeader>();
197-
let space = header_size + full_auth_data.len();
198-
let rent = (space as u64)
199-
.checked_mul(6960)
200-
.and_then(|val| val.checked_add(897840))
201-
.ok_or(ProgramError::ArithmeticOverflow)?;
211+
// Secp256r1 needs extra 4 bytes for counter prefix
212+
let variable_size = if args.authority_type == 1 {
213+
4 + full_auth_data.len()
214+
} else {
215+
full_auth_data.len()
216+
};
217+
let space = header_size + variable_size;
218+
let rent_lamports = rent.minimum_balance(space);
202219

203220
// Use secure transfer-allocate-assign pattern to prevent DoS (Issue #4)
204221
let bump_arr = [bump];
@@ -214,7 +231,7 @@ pub fn process_add_authority(
214231
new_auth_pda,
215232
system_program,
216233
space,
217-
rent,
234+
rent_lamports,
218235
program_id,
219236
&seeds,
220237
)?;

program/src/processor/transfer_ownership.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ pub fn process(
112112
return Err(ProgramError::IllegalOwner);
113113
}
114114

115+
// Validate system_program is the correct System Program (audit N2)
116+
if !sol_assert_bytes_eq(
117+
system_program.key().as_ref(),
118+
&crate::utils::SYSTEM_PROGRAM_ID,
119+
32,
120+
) {
121+
return Err(ProgramError::IncorrectProgramId);
122+
}
123+
115124
if !current_owner.is_writable() {
116125
return Err(ProgramError::InvalidAccountData);
117126
}

program/src/utils.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use pinocchio::{
77
ProgramResult,
88
};
99

10+
/// System Program ID (11111111111111111111111111111111)
11+
pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32];
12+
1013
/// Wrapper around the `sol_get_stack_height` syscall
1114
pub fn get_stack_height() -> u64 {
1215
#[cfg(target_os = "solana")]

0 commit comments

Comments
 (0)