diff --git a/programs/bpf/c/src/invoke/invoke.c b/programs/bpf/c/src/invoke/invoke.c index 0bded4aaac..4b0cbc802f 100644 --- a/programs/bpf/c/src/invoke/invoke.c +++ b/programs/bpf/c/src/invoke/invoke.c @@ -9,6 +9,7 @@ static const uint8_t TEST_PRIVILEGE_ESCALATION_SIGNER = 2; static const uint8_t TEST_PRIVILEGE_ESCALATION_WRITABLE = 3; static const uint8_t TEST_PPROGRAM_NOT_EXECUTABLE = 4; static const uint8_t TEST_EMPTY_ACCOUNTS_SLICE = 5; +static const uint8_t TEST_CAP_SEEDS = 6; static const int MINT_INDEX = 0; static const int ARGUMENT_INDEX = 1; @@ -282,6 +283,33 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert(SUCCESS == sol_invoke(&instruction, 0, 0)); } + case TEST_CAP_SEEDS: { + sol_log("Test cap seeds"); + { + SolAccountMeta arguments[] = {}; + uint8_t data[] = {}; + const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, + arguments, SOL_ARRAY_SIZE(arguments), + data, SOL_ARRAY_SIZE(data)}; + uint8_t seed[] = {"seed"}; + const SolSignerSeed seeds[] = { + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, {seed, SOL_ARRAY_SIZE(seed)}, + {seed, SOL_ARRAY_SIZE(seed)}, + }; + const SolSignerSeeds signers_seeds[] = {{seeds, SOL_ARRAY_SIZE(seeds)}}; + sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts, + SOL_ARRAY_SIZE(accounts), + signers_seeds, + SOL_ARRAY_SIZE(signers_seeds))); + } + } default: sol_panic(); } diff --git a/programs/bpf/rust/invoke/src/lib.rs b/programs/bpf/rust/invoke/src/lib.rs index 901e390618..a59c07abb7 100644 --- a/programs/bpf/rust/invoke/src/lib.rs +++ b/programs/bpf/rust/invoke/src/lib.rs @@ -21,6 +21,7 @@ const TEST_PRIVILEGE_ESCALATION_SIGNER: u8 = 2; const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3; const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4; const TEST_EMPTY_ACCOUNTS_SLICE: u8 = 5; +const TEST_CAP_SEEDS: u8 = 6; // const MINT_INDEX: usize = 0; const ARGUMENT_INDEX: usize = 1; @@ -362,6 +363,18 @@ fn process_instruction( let instruction = create_instruction(*accounts[INVOKED_PROGRAM_INDEX].key, &[], vec![]); invoke(&instruction, &[])?; } + TEST_CAP_SEEDS => { + msg!("Test program max seeds"); + let instruction = create_instruction(*accounts[INVOKED_PROGRAM_INDEX].key, &[], vec![]); + invoke_signed( + &instruction, + accounts, + &[&[ + b"1", b"2", b"3", b"4", b"5", b"6", b"7", b"8", b"9", b"0", b"1", b"2", b"3", + b"4", b"5", b"6", b"7", + ]], + )?; + } _ => panic!(), } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index b4d68efcd3..d61a36ce50 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -446,6 +446,7 @@ fn test_program_bpf_invoke() { const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3; const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4; const TEST_EMPTY_ACCOUNTS_SLICE: u8 = 5; + const TEST_CAP_SEEDS: u8 = 6; #[allow(dead_code)] #[derive(Debug)] @@ -720,6 +721,33 @@ fn test_program_bpf_invoke() { TransactionError::InstructionError(0, InstructionError::MissingAccount) ); + let instruction = Instruction::new( + invoke_program_id, + &[TEST_CAP_SEEDS, bump_seed1, bump_seed2, bump_seed3], + account_metas.clone(), + ); + let message = Message::new(&[instruction], Some(&mint_pubkey)); + let tx = Transaction::new( + &[ + &mint_keypair, + &argument_keypair, + &invoked_argument_keypair, + &from_keypair, + ], + message.clone(), + bank.last_blockhash(), + ); + let (result, inner_instructions) = process_transaction_and_record_inner(&bank, tx); + let invoked_programs: Vec = inner_instructions[0] + .iter() + .map(|ix| message.account_keys[ix.program_id_index as usize].clone()) + .collect(); + assert_eq!(invoked_programs, vec![]); + assert_eq!( + result.unwrap_err(), + TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded) + ); + // Check final state assert_eq!(43, bank.get_balance(&derived_key1)); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 14e577ec2e..f8f7dcd22c 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -829,9 +829,6 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { ro_regions, self.loader_id )?; - if signers_seeds.len() > MAX_SEEDS { - return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()); - } for signer_seeds in signers_seeds.iter() { let untranslated_seeds = translate_slice!( &[u8], @@ -840,6 +837,12 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { ro_regions, self.loader_id )?; + if untranslated_seeds.len() > MAX_SEEDS { + return Err(SyscallError::InstructionError( + InstructionError::MaxSeedLengthExceeded, + ) + .into()); + } let seeds = untranslated_seeds .iter() .map(|untranslated_seed| { @@ -1085,9 +1088,6 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { ro_regions, self.loader_id )?; - if signers_seeds.len() > MAX_SEEDS { - return Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()); - } Ok(signers_seeds .iter() .map(|signer_seeds| { @@ -1098,6 +1098,12 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { ro_regions, self.loader_id )?; + if seeds.len() > MAX_SEEDS { + return Err(SyscallError::InstructionError( + InstructionError::MaxSeedLengthExceeded, + ) + .into()); + } let seeds_bytes = seeds .iter() .map(|seed| {