Cap CPI signers (#14021)

This commit is contained in:
Jack May 2020-12-09 02:14:53 -08:00 committed by GitHub
parent e1872a450a
commit e1a4251b07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 36 deletions

View File

@ -37,17 +37,17 @@ fn rerun_if_changed(files: &[&str], directories: &[&str], excludes: &[&str]) {
fn main() {
let bpf_c = env::var("CARGO_FEATURE_BPF_C").is_ok();
if bpf_c {
let install_dir =
"OUT_DIR=../target/".to_string() + &env::var("PROFILE").unwrap() + &"/bpf".to_string();
let install_dir =
"OUT_DIR=../target/".to_string() + &env::var("PROFILE").unwrap() + &"/bpf".to_string();
println!("cargo:warning=(not a warning) Building C-based BPF programs");
assert!(Command::new("make")
.current_dir("c")
.arg("programs")
.arg(&install_dir)
.status()
.expect("Failed to build C-based BPF programs")
.success());
assert!(Command::new("make")
.current_dir("c")
.arg("programs")
.arg(&install_dir)
.status()
.expect("Failed to build C-based BPF programs")
.success());
rerun_if_changed(&["c/makefile"], &["c/src", "../../sdk"], &["/target/"]);
}

View File

@ -10,6 +10,7 @@ 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 uint8_t TEST_CAP_SIGNERS = 7;
static const int MINT_INDEX = 0;
static const int ARGUMENT_INDEX = 1;
@ -285,30 +286,66 @@ extern uint64_t entrypoint(const uint8_t *input) {
}
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)));
}
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)));
}
case TEST_CAP_SIGNERS: {
sol_log("Test cap signers");
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 seed1[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed2[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed3[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed4[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed5[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed6[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed7[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed8[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed9[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed10[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed11[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed12[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed13[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed14[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed15[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed16[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeed seed17[] = {{seed, SOL_ARRAY_SIZE(seed)}};
const SolSignerSeeds signers_seeds[] = {
{seed1, SOL_ARRAY_SIZE(seed1)}, {seed2, SOL_ARRAY_SIZE(seed2)},
{seed3, SOL_ARRAY_SIZE(seed3)}, {seed4, SOL_ARRAY_SIZE(seed4)},
{seed5, SOL_ARRAY_SIZE(seed5)}, {seed6, SOL_ARRAY_SIZE(seed6)},
{seed7, SOL_ARRAY_SIZE(seed7)}, {seed8, SOL_ARRAY_SIZE(seed8)},
{seed9, SOL_ARRAY_SIZE(seed9)}, {seed10, SOL_ARRAY_SIZE(seed10)},
{seed11, SOL_ARRAY_SIZE(seed11)}, {seed12, SOL_ARRAY_SIZE(seed12)},
{seed13, SOL_ARRAY_SIZE(seed13)}, {seed14, SOL_ARRAY_SIZE(seed14)},
{seed15, SOL_ARRAY_SIZE(seed15)}, {seed16, SOL_ARRAY_SIZE(seed16)},
{seed17, SOL_ARRAY_SIZE(seed17)}};
sol_assert(SUCCESS == sol_invoke_signed(
&instruction, accounts, SOL_ARRAY_SIZE(accounts),
signers_seeds, SOL_ARRAY_SIZE(signers_seeds)));
}
default:
sol_panic();

View File

@ -22,6 +22,7 @@ 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 TEST_CAP_SIGNERS: u8 = 7;
// const MINT_INDEX: usize = 0;
const ARGUMENT_INDEX: usize = 1;
@ -385,6 +386,33 @@ fn process_instruction(
]],
)?;
}
TEST_CAP_SIGNERS => {
msg!("Test program max signers");
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!(),
}

View File

@ -24,12 +24,10 @@ use solana_sdk::{
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount,
loader_instruction,
message::Message,
process_instruction::{BpfComputeBudget, InvokeContext, MockInvokeContext},
process_instruction::{InvokeContext, MockInvokeContext},
pubkey::Pubkey,
signature::{Keypair, Signer},
system_instruction,
sysvar::{clock, fees, rent, slot_hashes, stake_history},
transaction::{Transaction, TransactionError},
};
@ -71,6 +69,7 @@ fn read_bpf_program(name: &str) -> Vec<u8> {
elf
}
#[cfg(feature = "bpf_rust")]
fn write_bpf_program(
bank_client: &BankClient,
loader_id: &Pubkey,
@ -78,6 +77,8 @@ fn write_bpf_program(
program_keypair: &Keypair,
elf: &[u8],
) {
use solana_sdk::loader_instruction;
let chunk_size = 256; // Size of chunk just needs to fit into tx
let mut offset = 0;
for chunk in elf.chunks(chunk_size) {
@ -522,6 +523,7 @@ fn test_program_bpf_invoke() {
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
const TEST_EMPTY_ACCOUNTS_SLICE: u8 = 5;
const TEST_CAP_SEEDS: u8 = 6;
const TEST_CAP_SIGNERS: u8 = 7;
#[allow(dead_code)]
#[derive(Debug)]
@ -823,6 +825,33 @@ fn test_program_bpf_invoke() {
TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded)
);
let instruction = Instruction::new(
invoke_program_id,
&[TEST_CAP_SIGNERS, 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<Pubkey> = 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::Custom(194969602))
);
// Check final state
assert_eq!(43, bank.get_balance(&derived_key1));
@ -986,6 +1015,8 @@ fn test_program_bpf_ro_modify() {
#[cfg(feature = "bpf_rust")]
#[test]
fn test_program_bpf_call_depth() {
use solana_sdk::process_instruction::BpfComputeBudget;
solana_logger::setup();
println!("Test program: solana_bpf_rust_call_depth");
@ -1139,6 +1170,8 @@ fn test_program_bpf_instruction_introspection() {
#[cfg(feature = "bpf_rust")]
#[test]
fn test_program_bpf_test_use_latest_executor() {
use solana_sdk::{loader_instruction, system_instruction};
solana_logger::setup();
let GenesisConfigInfo {
@ -1229,6 +1262,8 @@ fn test_program_bpf_test_use_latest_executor() {
#[cfg(feature = "bpf_rust")]
#[test]
fn test_program_bpf_test_use_latest_executor2() {
use solana_sdk::{loader_instruction, system_instruction};
solana_logger::setup();
let GenesisConfigInfo {

View File

@ -37,6 +37,9 @@ use std::{
};
use thiserror::Error as ThisError;
/// Maximum signers
pub const MAX_SIGNERS: usize = 16;
/// Error definitions
#[derive(Debug, ThisError, PartialEq)]
pub enum SyscallError {
@ -60,6 +63,8 @@ pub enum SyscallError {
PrivilegeEscalation,
#[error("Unaligned pointer")]
UnalignedPointer,
#[error("Too many signers")]
TooManySigners,
}
impl From<SyscallError> for EbpfError<BPFError> {
fn from(error: SyscallError) -> Self {
@ -923,6 +928,9 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
signers_seeds_len,
self.loader_id,
)?;
if signers_seeds.len() > MAX_SIGNERS {
return Err(SyscallError::TooManySigners.into());
}
for signer_seeds in signers_seeds.iter() {
let untranslated_seeds = translate_slice::<&[u8]>(
memory_mapping,
@ -1178,6 +1186,9 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
signers_seeds_len,
self.loader_id,
)?;
if signers_seeds.len() > MAX_SIGNERS {
return Err(SyscallError::TooManySigners.into());
}
Ok(signers_seeds
.iter()
.map(|signer_seeds| {