Skip to content

Commit 51506b1

Browse files
committed
fix(lazer): fetch message offset and data from sysvar and verify message data
1 parent 7c121bb commit 51506b1

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

lazer/contracts/solana/programs/pyth-lazer-solana-contract/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ pub mod pyth_lazer_solana_contract {
197197
message_data: Vec<u8>,
198198
ed25519_instruction_index: u16,
199199
signature_index: u8,
200-
message_offset: u16,
201200
) -> Result<VerifiedMessage> {
202201
system_program::transfer(
203202
CpiContext::new(
@@ -216,7 +215,6 @@ pub mod pyth_lazer_solana_contract {
216215
&message_data,
217216
ed25519_instruction_index,
218217
signature_index,
219-
message_offset,
220218
)
221219
.map_err(|err| {
222220
msg!("signature verification error: {:?}", err);

lazer/contracts/solana/programs/pyth-lazer-solana-contract/src/signature.rs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use {
22
crate::Storage,
33
anchor_lang::{
44
prelude::{borsh, AccountInfo, Clock, ProgramError, Pubkey, SolanaSysvar},
5-
solana_program::{ed25519_program, pubkey::PUBKEY_BYTES, sysvar},
5+
solana_program::{
6+
ed25519_program, program_memory::sol_memcmp, pubkey::PUBKEY_BYTES, sysvar,
7+
},
68
AnchorDeserialize, AnchorSerialize,
79
},
810
bytemuck::{cast_slice, checked::try_cast_slice, Pod, Zeroable},
@@ -127,6 +129,8 @@ pub enum SignatureVerificationError {
127129
InvalidStorageData,
128130
#[error("not a trusted signer")]
129131
NotTrustedSigner,
132+
#[error("invalid message data")]
133+
InvalidMessageData,
130134
}
131135

132136
impl From<SignatureVerificationError> for ProgramError {
@@ -148,6 +152,10 @@ impl From<SignatureVerificationError> for anchor_lang::error::Error {
148152
}
149153
}
150154

155+
fn slice_eq(a: &[u8], b: &[u8]) -> bool {
156+
a.len() == b.len() && sol_memcmp(a, b, a.len()) == 0
157+
}
158+
151159
/// Verifies a ed25519 signature on Solana by checking that the transaction contains
152160
/// a correct call to the built-in `ed25519_program`.
153161
///
@@ -163,7 +171,6 @@ pub fn verify_message(
163171
message_data: &[u8],
164172
ed25519_instruction_index: u16,
165173
signature_index: u8,
166-
message_offset: u16,
167174
) -> Result<VerifiedMessage, SignatureVerificationError> {
168175
const SOLANA_FORMAT_MAGIC_LE: u32 = 2182742457;
169176

@@ -175,25 +182,25 @@ pub fn verify_message(
175182
return Err(SignatureVerificationError::Ed25519InstructionMustPrecedeCurrentInstruction);
176183
}
177184

178-
let instruction = sysvar::instructions::load_instruction_at_checked(
185+
let ed25519_instruction = sysvar::instructions::load_instruction_at_checked(
179186
ed25519_instruction_index.into(),
180187
instructions_sysvar,
181188
)
182189
.map_err(SignatureVerificationError::LoadInstructionAtFailed)?;
183190

184-
if instruction.program_id != ed25519_program::ID {
191+
if ed25519_instruction.program_id != ed25519_program::ID {
185192
return Err(SignatureVerificationError::InvalidEd25519InstructionProgramId);
186193
}
187-
if instruction.data.len() < ED25519_PROGRAM_INPUT_HEADER_LEN {
194+
if ed25519_instruction.data.len() < ED25519_PROGRAM_INPUT_HEADER_LEN {
188195
return Err(SignatureVerificationError::InvalidEd25519InstructionDataLength);
189196
}
190197

191-
let num_signatures = instruction.data[0];
198+
let num_signatures = ed25519_instruction.data[0];
192199
if signature_index >= num_signatures {
193200
return Err(SignatureVerificationError::InvalidSignatureIndex);
194201
}
195202
let args: &[Ed25519SignatureOffsets] =
196-
try_cast_slice(&instruction.data[ED25519_PROGRAM_INPUT_HEADER_LEN..])
203+
try_cast_slice(&ed25519_instruction.data[ED25519_PROGRAM_INPUT_HEADER_LEN..])
197204
.map_err(|_| SignatureVerificationError::InvalidEd25519InstructionDataLength)?;
198205

199206
let args_len = args
@@ -205,19 +212,37 @@ pub fn verify_message(
205212
}
206213
let offsets = &args[usize::from(signature_index)];
207214

208-
let expected_signature_offset = message_offset
209-
.checked_add(MAGIC_LEN)
215+
let message_offset = offsets
216+
.signature_offset
217+
.checked_sub(MAGIC_LEN)
210218
.ok_or(SignatureVerificationError::MessageOffsetOverflow)?;
211-
if offsets.signature_offset != expected_signature_offset {
212-
return Err(SignatureVerificationError::InvalidSignatureOffset);
219+
220+
let self_instruction = sysvar::instructions::load_instruction_at_checked(
221+
self_instruction_index.into(),
222+
instructions_sysvar,
223+
)
224+
.map_err(SignatureVerificationError::LoadInstructionAtFailed)?;
225+
226+
let message_end_offset = offsets
227+
.message_data_offset
228+
.checked_add(offsets.message_data_size)
229+
.ok_or(SignatureVerificationError::MessageOffsetOverflow)?;
230+
let expected_message_data = self_instruction
231+
.data
232+
.get(usize::from(message_offset)..usize::from(message_end_offset))
233+
.ok_or(SignatureVerificationError::InvalidMessageOffset)?;
234+
235+
if !slice_eq(expected_message_data, message_data) {
236+
return Err(SignatureVerificationError::InvalidMessageData);
213237
}
214238

215239
let magic = LE::read_u32(&message_data[..MAGIC_LEN.into()]);
216240
if magic != SOLANA_FORMAT_MAGIC_LE {
217241
return Err(SignatureVerificationError::FormatMagicMismatch);
218242
}
219243

220-
let expected_public_key_offset = expected_signature_offset
244+
let expected_public_key_offset = offsets
245+
.signature_offset
221246
.checked_add(SIGNATURE_LEN)
222247
.ok_or(SignatureVerificationError::MessageOffsetOverflow)?;
223248
if offsets.public_key_offset != expected_public_key_offset {

lazer/contracts/solana/programs/pyth-lazer-solana-contract/tests/test1.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ impl Setup {
134134
message_data: message.to_vec(),
135135
ed25519_instruction_index: 0,
136136
signature_index: 0,
137-
message_offset,
138137
}
139138
.data(),
140139
vec![

0 commit comments

Comments
 (0)