Add Program loader/environment instruction errors (#14120)

This commit is contained in:
Jack May
2020-12-15 09:54:07 -08:00
committed by GitHub
parent 03fc031611
commit d513b0c4ca
4 changed files with 31 additions and 30 deletions

View File

@ -890,7 +890,7 @@ fn test_program_bpf_invoke() {
assert_eq!(invoked_programs, vec![]); assert_eq!(invoked_programs, vec![]);
assert_eq!( assert_eq!(
result.unwrap_err(), result.unwrap_err(),
TransactionError::InstructionError(0, InstructionError::Custom(194969602)) TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
); );
// Check final state // Check final state
@ -1033,7 +1033,7 @@ fn test_program_bpf_ro_modify() {
let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
assert_eq!( assert_eq!(
result.unwrap_err().unwrap(), result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
); );
let instruction = Instruction::new(program_pubkey, &[3_u8], account_metas.clone()); let instruction = Instruction::new(program_pubkey, &[3_u8], account_metas.clone());
@ -1041,7 +1041,7 @@ fn test_program_bpf_ro_modify() {
let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
assert_eq!( assert_eq!(
result.unwrap_err().unwrap(), result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
); );
let instruction = Instruction::new(program_pubkey, &[4_u8], account_metas.clone()); let instruction = Instruction::new(program_pubkey, &[4_u8], account_metas.clone());
@ -1049,7 +1049,7 @@ fn test_program_bpf_ro_modify() {
let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message); let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
assert_eq!( assert_eq!(
result.unwrap_err().unwrap(), result.unwrap_err().unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(0xb9f0002)) TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
); );
} }

View File

@ -13,7 +13,6 @@ use crate::{
serialization::{deserialize_parameters, serialize_parameters}, serialization::{deserialize_parameters, serialize_parameters},
syscalls::SyscallError, syscalls::SyscallError,
}; };
use num_derive::{FromPrimitive, ToPrimitive};
use solana_rbpf::{ use solana_rbpf::{
ebpf::MM_HEAP_START, ebpf::MM_HEAP_START,
error::{EbpfError, UserDefinedError}, error::{EbpfError, UserDefinedError},
@ -26,7 +25,6 @@ use solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState}, bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Clock, clock::Clock,
decode_error::DecodeError,
entrypoint::SUCCESS, entrypoint::SUCCESS,
feature_set::bpf_compute_budget_balancing, feature_set::bpf_compute_budget_balancing,
instruction::InstructionError, instruction::InstructionError,
@ -48,22 +46,6 @@ solana_sdk::declare_builtin!(
solana_bpf_loader_program::process_instruction solana_bpf_loader_program::process_instruction
); );
/// Errors returned by the BPFLoader if the VM fails to run the program
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
pub enum BPFLoaderError {
#[error("failed to create virtual machine")]
VirtualMachineCreationFailed = 0x0b9f_0001,
#[error("virtual machine failed to run the program to completion")]
VirtualMachineFailedToRunProgram = 0x0b9f_0002,
#[error("failed to compile program")]
JustInTimeCompilationFailed = 0x0b9f_0003,
}
impl<E> DecodeError<E> for BPFLoaderError {
fn type_of() -> &'static str {
"BPFLoaderError"
}
}
/// Errors returned by functions the BPF Loader registers with the VM /// Errors returned by functions the BPF Loader registers with the VM
#[derive(Debug, Error, PartialEq)] #[derive(Debug, Error, PartialEq)]
pub enum BPFError { pub enum BPFError {
@ -107,6 +89,8 @@ pub fn create_and_cache_executor(
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
use_jit: bool, use_jit: bool,
) -> Result<Arc<BPFExecutor>, InstructionError> { ) -> Result<Arc<BPFExecutor>, InstructionError> {
let logger = invoke_context.get_logger();
let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
let mut program = Executable::<BPFError, ThisInstructionMeter>::from_elf( let mut program = Executable::<BPFError, ThisInstructionMeter>::from_elf(
data, data,
@ -127,11 +111,16 @@ pub fn create_and_cache_executor(
!invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()), !invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()),
) )
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
let syscall_registry = syscalls::register_syscalls(invoke_context) let syscall_registry = syscalls::register_syscalls(invoke_context).map_err(|e| {
.map_err(|e| map_ebpf_error(invoke_context, e))?; log!(logger, "Failed to register syscalls: {}", e);
InstructionError::ProgramEnvironmentSetupFailure
})?;
program.set_syscall_registry(syscall_registry); program.set_syscall_registry(syscall_registry);
if use_jit && program.jit_compile().is_err() { if use_jit {
return Err(BPFLoaderError::JustInTimeCompilationFailed.into()); if let Err(err) = program.jit_compile() {
log!(logger, "Failed to compile program {:?}", err);
return Err(InstructionError::ProgramFailedToCompile);
}
} }
let executor = Arc::new(BPFExecutor { program }); let executor = Arc::new(BPFExecutor { program });
invoke_context.add_executor(key, executor.clone()); invoke_context.add_executor(key, executor.clone());
@ -682,7 +671,7 @@ impl Executor for BPFExecutor {
Ok(info) => info, Ok(info) => info,
Err(e) => { Err(e) => {
log!(logger, "Failed to create BPF VM: {}", e); log!(logger, "Failed to create BPF VM: {}", e);
return Err(BPFLoaderError::VirtualMachineCreationFailed.into()); return Err(InstructionError::ProgramEnvironmentSetupFailure);
} }
}; };
@ -721,7 +710,10 @@ impl Executor for BPFExecutor {
EbpfError::UserError(BPFError::SyscallError( EbpfError::UserError(BPFError::SyscallError(
SyscallError::InstructionError(error), SyscallError::InstructionError(error),
)) => error, )) => error,
_ => BPFLoaderError::VirtualMachineFailedToRunProgram.into(), err => {
log!(logger, "Program failed to complete: {:?}", err);
InstructionError::ProgramFailedToComplete
}
}; };
stable_log::program_failure(&logger, program.unsigned_key(), &error); stable_log::program_failure(&logger, program.unsigned_key(), &error);
@ -1010,7 +1002,7 @@ mod tests {
Arc::new(FeatureSet::default()), Arc::new(FeatureSet::default()),
); );
assert_eq!( assert_eq!(
Err(InstructionError::Custom(194969602)), Err(InstructionError::ProgramFailedToComplete),
process_instruction(&bpf_loader::id(), &keyed_accounts, &[], &mut invoke_context) process_instruction(&bpf_loader::id(), &keyed_accounts, &[], &mut invoke_context)
); );

View File

@ -114,7 +114,7 @@ pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;
pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5; pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;
type BankStatusCache = StatusCache<Result<()>>; type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "9b9RfyiGPNGcMyP78YSD799ghJSTsGvqHTsJtQo8uqGX")] #[frozen_abi(digest = "GSPuprru1pomsgvopKG7XRWiXdqdXJdLPkgJ2arPbkXM")]
pub type BankSlotDelta = SlotDelta<Result<()>>; pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>; type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<Account>)>>; type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<Account>)>>;

View File

@ -171,6 +171,15 @@ pub enum InstructionError {
/// Cross-program invocation with unauthorized signer or writable account /// Cross-program invocation with unauthorized signer or writable account
#[error("Cross-program invocation with unauthorized signer or writable account")] #[error("Cross-program invocation with unauthorized signer or writable account")]
PrivilegeEscalation, PrivilegeEscalation,
#[error("Failed to create program execution environment")]
ProgramEnvironmentSetupFailure,
#[error("Program failed to complete")]
ProgramFailedToComplete,
#[error("Program failed to compile")]
ProgramFailedToCompile,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]