diff --git a/pythnet/remote-executor/Cargo.lock b/pythnet/remote-executor/Cargo.lock index 45762427..a2e05e66 100644 --- a/pythnet/remote-executor/Cargo.lock +++ b/pythnet/remote-executor/Cargo.lock @@ -4906,7 +4906,7 @@ dependencies = [ [[package]] name = "wormhole-core" version = "0.1.0" -source = "git+https://github.com/guibescos/wormhole?branch=gbescos/sdk-solana#2a6169c646a78d76407323d138fa4aeb09b1655a" +source = "git+https://github.com/guibescos/wormhole?branch=reisen/sdk-solana#61bb2fb691a8df0aa0e42a21632e43b392ffa90f" dependencies = [ "borsh", "bstr", @@ -4922,7 +4922,7 @@ dependencies = [ [[package]] name = "wormhole-solana" version = "0.1.0" -source = "git+https://github.com/guibescos/wormhole?branch=gbescos/sdk-solana#2a6169c646a78d76407323d138fa4aeb09b1655a" +source = "git+https://github.com/guibescos/wormhole?branch=reisen/sdk-solana#61bb2fb691a8df0aa0e42a21632e43b392ffa90f" dependencies = [ "borsh", "bstr", diff --git a/pythnet/remote-executor/programs/remote-executor/Cargo.toml b/pythnet/remote-executor/programs/remote-executor/Cargo.toml index 9a483ef5..63db3c1f 100644 --- a/pythnet/remote-executor/programs/remote-executor/Cargo.toml +++ b/pythnet/remote-executor/programs/remote-executor/Cargo.toml @@ -20,8 +20,8 @@ overflow-checks = true [dependencies] anchor-lang = {version = "0.25.0", features = ["init-if-needed"]} -wormhole-solana = { git = "https://github.com/guibescos/wormhole", branch = "gbescos/sdk-solana"} -wormhole-core = { git = "https://github.com/guibescos/wormhole", branch = "gbescos/sdk-solana"} +wormhole-solana = { git = "https://github.com/guibescos/wormhole", branch = "reisen/sdk-solana"} +wormhole-core = { git = "https://github.com/guibescos/wormhole", branch = "reisen/sdk-solana"} boolinator = "2.4.0" [dev-dependencies] diff --git a/pythnet/remote-executor/programs/remote-executor/src/error.rs b/pythnet/remote-executor/programs/remote-executor/src/error.rs index d7c5635d..1b90984d 100644 --- a/pythnet/remote-executor/programs/remote-executor/src/error.rs +++ b/pythnet/remote-executor/programs/remote-executor/src/error.rs @@ -8,4 +8,5 @@ pub enum ExecutorError { GovernanceHeaderInvalidModule, GovernanceHeaderInvalidAction, GovernanceHeaderInvalidReceiverChain, + PostedVaaHeaderWrongMagicNumber, } diff --git a/pythnet/remote-executor/programs/remote-executor/src/lib.rs b/pythnet/remote-executor/programs/remote-executor/src/lib.rs index 4e16c2aa..edb846f6 100644 --- a/pythnet/remote-executor/programs/remote-executor/src/lib.rs +++ b/pythnet/remote-executor/programs/remote-executor/src/lib.rs @@ -17,13 +17,13 @@ use wormhole::Chain::{ }; mod error; -mod state; +pub mod state; #[cfg(test)] mod tests; //Anchor requires the program to declare its own id -declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); +declare_id!("exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"); #[program] pub mod remote_executor { @@ -65,14 +65,14 @@ pub mod remote_executor { } } -const EXECUTOR_KEY_SEED: &str = "EXECUTOR_KEY"; -const CLAIM_RECORD_SEED: &str = "CLAIM_RECORD"; +pub const EXECUTOR_KEY_SEED: &str = "EXECUTOR_KEY"; +pub const CLAIM_RECORD_SEED: &str = "CLAIM_RECORD"; #[derive(Accounts)] pub struct ExecutePostedVaa<'info> { #[account(mut)] pub payer: Signer<'info>, - #[account(constraint = Chain::from(posted_vaa.emitter_chain) == Solana @ ExecutorError::EmitterChainNotSolana, constraint = posted_vaa.sequence > claim_record.sequence @ExecutorError::NonIncreasingSequence )] + #[account(constraint = Chain::from(posted_vaa.emitter_chain) == Solana @ ExecutorError::EmitterChainNotSolana, constraint = posted_vaa.sequence > claim_record.sequence @ExecutorError::NonIncreasingSequence, constraint = (&posted_vaa.magic == b"vaa" || &posted_vaa.magic == b"msg" || &posted_vaa.magic == b"msu") @ExecutorError::PostedVaaHeaderWrongMagicNumber )] pub posted_vaa: Account<'info, AnchorVaa>, /// The reason claim_record has different seeds than executor_key is that executor key might need to pay in the CPI, so we want it to be a native wallet #[account(init_if_needed, space = 8 + get_packed_len::(), payer=payer, seeds = [CLAIM_RECORD_SEED.as_bytes(), &posted_vaa.emitter_address], bump)] diff --git a/pythnet/remote-executor/programs/remote-executor/src/state/posted_vaa.rs b/pythnet/remote-executor/programs/remote-executor/src/state/posted_vaa.rs index 07e4904f..e36dbc08 100644 --- a/pythnet/remote-executor/programs/remote-executor/src/state/posted_vaa.rs +++ b/pythnet/remote-executor/programs/remote-executor/src/state/posted_vaa.rs @@ -49,5 +49,6 @@ impl Deref for AnchorVaa { #[derive(Clone, AnchorDeserialize, AnchorSerialize)] pub struct AnchorVaa { + pub magic: [u8; 3], pub vaa: VAA, } diff --git a/pythnet/remote-executor/programs/remote-executor/src/tests/executor_simulator.rs b/pythnet/remote-executor/programs/remote-executor/src/tests/executor_simulator.rs index 16f00346..4619dff5 100644 --- a/pythnet/remote-executor/programs/remote-executor/src/tests/executor_simulator.rs +++ b/pythnet/remote-executor/programs/remote-executor/src/tests/executor_simulator.rs @@ -74,6 +74,7 @@ pub enum VaaAttack { WrongOwner, WrongData, WrongEmitterChain, + WrongVaaMagic, } impl ExecutorBench { @@ -154,6 +155,11 @@ impl ExecutorBench { _ => Chain::Solana.into(), }; + let vaa_magic = match validity { + VaaAttack::WrongVaaMagic => b"xxx", + _ => b"vaa", + }; + let owner: Pubkey = match validity { VaaAttack::WrongOwner => Pubkey::new_unique(), _ => AnchorVaa::owner(), @@ -169,17 +175,20 @@ impl ExecutorBench { let payload_bytes = payload.try_to_vec().unwrap(); - let vaa = VAA { - vaa_version: 0, - consistency_level: 0, - vaa_time: 0, - vaa_signature_account: Pubkey::new_unique(), - submission_time: 0, - nonce: 0, - sequence: self.seqno.get(&emitter).unwrap_or(&0) + 1, - emitter_chain, - emitter_address: emitter.to_bytes(), - payload: payload_bytes, + let vaa = AnchorVaa { + magic: *vaa_magic, + vaa: VAA { + vaa_version: 0, + consistency_level: 0, + vaa_time: 0, + vaa_signature_account: Pubkey::new_unique(), + submission_time: 0, + nonce: 0, + sequence: self.seqno.get(&emitter).unwrap_or(&0) + 1, + emitter_chain, + emitter_address: emitter.to_bytes(), + payload: payload_bytes, + }, }; *self.seqno.entry(*emitter).or_insert(0) += 1; @@ -278,7 +287,7 @@ impl ExecutorSimulator { signers: &Vec<&Keypair>, executor_attack: ExecutorAttack, ) -> Result<(), BanksClientError> { - let posted_vaa_data: VAA = self + let posted_vaa_data: AnchorVaa = self .banks_client .get_account_data_with_borsh(*posted_vaa_address) .await diff --git a/pythnet/remote-executor/programs/remote-executor/src/tests/test_adversarial.rs b/pythnet/remote-executor/programs/remote-executor/src/tests/test_adversarial.rs index 4f2e07ea..d5215b89 100644 --- a/pythnet/remote-executor/programs/remote-executor/src/tests/test_adversarial.rs +++ b/pythnet/remote-executor/programs/remote-executor/src/tests/test_adversarial.rs @@ -73,6 +73,16 @@ async fn test_adversarial() { VaaAttack::WrongEmitterChain, ); + let vaa_account_wrong_vaa_magic = bench.add_vaa_account( + &emitter, + &vec![transfer( + &executor_key, + &&receiver, + Rent::default().minimum_balance(0), + )], + VaaAttack::WrongVaaMagic, + ); + // The goal of this account is creating a claim_record that the attacker is going to try to use to impersonate // the right claim_record let vaa_account_valid_2 = bench.add_vaa_account(&emitter_2, &vec![], VaaAttack::None); @@ -115,6 +125,15 @@ async fn test_adversarial() { ExecutorError::EmitterChainNotSolana.into() ); + // VAA has wrong magic number + assert_eq!( + sim.execute_posted_vaa(&vaa_account_wrong_vaa_magic, &vec![], ExecutorAttack::None) + .await + .unwrap_err() + .unwrap(), + ExecutorError::PostedVaaHeaderWrongMagicNumber.into() + ); + // Claim record does not correspond to the emitter's claim record // Next error is privilege scalation because anchor tries to create the account at wrong address but signing with the right seeds assert_eq!(