From 38ee5c4dfb17ff1121b1bb31d5629724d3b3854b Mon Sep 17 00:00:00 2001 From: jackcmay Date: Wed, 31 Oct 2018 10:59:56 -0700 Subject: [PATCH] Program may not exit (#1669) Cap max executed instructions, report number of executed instructions --- programs/native/bpf_loader/Cargo.toml | 2 +- .../native/bpf_loader/src/bpf_verifier.rs | 2 +- programs/native/bpf_loader/src/lib.rs | 43 ++++++++++++++++--- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/programs/native/bpf_loader/Cargo.toml b/programs/native/bpf_loader/Cargo.toml index 7abc15066d..2f07efd88f 100644 --- a/programs/native/bpf_loader/Cargo.toml +++ b/programs/native/bpf_loader/Cargo.toml @@ -13,7 +13,7 @@ elf = "0.0.10" env_logger = "0.5.12" libc = "0.2.43" log = "0.4.2" -rbpf = "0.1.0" +solana_rbpf = "0.1.2" serde = "1.0.27" serde_derive = "1.0.27" solana-sdk = { path = "../../../sdk", version = "0.11.0" } diff --git a/programs/native/bpf_loader/src/bpf_verifier.rs b/programs/native/bpf_loader/src/bpf_verifier.rs index aff486564a..87ae0aadec 100644 --- a/programs/native/bpf_loader/src/bpf_verifier.rs +++ b/programs/native/bpf_loader/src/bpf_verifier.rs @@ -1,4 +1,4 @@ -use rbpf::ebpf; +use solana_rbpf::ebpf; use std::io::{Error, ErrorKind}; fn reject>(msg: S) -> Result<(), Error> { diff --git a/programs/native/bpf_loader/src/lib.rs b/programs/native/bpf_loader/src/lib.rs index 726381358d..3b1b9fea2c 100644 --- a/programs/native/bpf_loader/src/lib.rs +++ b/programs/native/bpf_loader/src/lib.rs @@ -5,11 +5,12 @@ extern crate byteorder; extern crate env_logger; #[macro_use] extern crate log; -extern crate rbpf; +extern crate solana_rbpf; extern crate solana_sdk; use bincode::deserialize; use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; +use solana_rbpf::{helpers, EbpfVmRaw}; use solana_sdk::account::KeyedAccount; use solana_sdk::loader_instruction::LoaderInstruction; use solana_sdk::pubkey::Pubkey; @@ -52,11 +53,12 @@ pub fn helper_printf(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u + size_arg(arg5) } -fn create_vm(prog: &[u8]) -> Result { - let mut vm = rbpf::EbpfVmRaw::new(None)?; +fn create_vm(prog: &[u8]) -> Result { + let mut vm = EbpfVmRaw::new(None)?; vm.set_verifier(bpf_verifier::check)?; + vm.set_max_instruction_count(36000)?; // 36000 is a wag, need to tune vm.set_program(&prog)?; - vm.register_helper(rbpf::helpers::BPF_TRACE_PRINTK_IDX, helper_printf)?; + vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helper_printf)?; Ok(vm) } @@ -107,9 +109,9 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) - if keyed_accounts[0].account.executable { let prog = keyed_accounts[0].account.userdata.clone(); - trace!("Call BPF, {} Instructions", prog.len() / 8); + trace!("Call BPF, {} instructions", prog.len() / 8); //dump_program(keyed_accounts[0].key, &prog); - let vm = match create_vm(&prog) { + let mut vm = match create_vm(&prog) { Ok(vm) => vm, Err(e) => { warn!("create_vm failed: {}", e); @@ -127,6 +129,10 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) - } } deserialize_parameters(&mut keyed_accounts[1..], &v); + trace!( + "BPF program executed {} instructions", + vm.get_last_instruction_count() + ); } else if let Ok(instruction) = deserialize(tx_data) { match instruction { LoaderInstruction::Write { offset, bytes } => { @@ -153,3 +159,28 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) - } true } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[should_panic(expected = "Error: Execution exceeded maximum number of instructions")] + fn test_non_terminating_program() { + #[rustfmt::skip] + let prog = &[ + 0xb7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r6 = 0 + 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = 0 + 0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r2 = 0 + 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r3 = 0 + 0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r4 = 0 + 0xbf, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r5 = r6 + 0x85, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // call 6 + 0x07, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // r6 + 1 + 0x05, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, // goto -8 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + let input = &mut [0x00]; + let mut vm = create_vm(prog).unwrap(); + vm.execute_program(input).unwrap(); + } +}