From baa4c6eaf219c0a7177b1e8985b3051917eccd04 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 17 Nov 2021 01:23:15 +0000 Subject: [PATCH] Bump solana_rbpf to version 0.2.13 (#18068) (#21302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Moves syscall_registry into the rbpf Executable constructor. * Adds the reject_unresolved_syscalls flag which is only set when deploying programs via the CLI. (cherry picked from commit 8d5c04e25704df0788d7a9808fd9d7594cd3ca8f) Co-authored-by: Alexander Meißner --- Cargo.lock | 8 +- cli/Cargo.toml | 2 +- cli/src/program.rs | 17 +- cli/tests/fixtures/noop.so | Bin 4440 -> 1592 bytes programs/bpf/Cargo.lock | 8 +- programs/bpf/Cargo.toml | 2 +- programs/bpf/benches/bpf_loader.rs | 36 +-- programs/bpf/tests/programs.rs | 14 +- programs/bpf_loader/Cargo.toml | 2 +- programs/bpf_loader/src/bpf_verifier.rs | 294 ------------------------ programs/bpf_loader/src/lib.rs | 25 +- programs/bpf_loader/src/syscalls.rs | 65 +++--- rbpf-cli/src/main.rs | 12 +- 13 files changed, 114 insertions(+), 371 deletions(-) delete mode 100644 programs/bpf_loader/src/bpf_verifier.rs diff --git a/Cargo.lock b/Cargo.lock index 738f2f6cd8..7ddddc7c88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1640,9 +1640,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69552f48b18aa6102ce0c82dd9bc9d3f8af5fc0a5797069b1b466b90570e39c" +checksum = "0b1800b95efee8ad4ef04517d4d69f8e209e763b1668f1179aeeedd0e454da55" dependencies = [ "log 0.4.14", "plain", @@ -5886,9 +5886,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c1c5bdfa63c68d848d95024c7f4335bae4b1917f7df2e48e2d945f4664a8b45" +checksum = "fc1dced9892c2b0273318ef4d8486112ea7c7a7b8eb563a20e7858ad921b4719" dependencies = [ "byteorder", "combine", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0d95c6ec13..9180183b30 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -40,7 +40,7 @@ solana-config-program = { path = "../programs/config", version = "=1.8.5" } solana-faucet = { path = "../faucet", version = "=1.8.5" } solana-logger = { path = "../logger", version = "=1.8.5" } solana-net-utils = { path = "../net-utils", version = "=1.8.5" } -solana_rbpf = "=0.2.11" +solana_rbpf = "=0.2.13" solana-remote-wallet = { path = "../remote-wallet", version = "=1.8.5" } solana-sdk = { path = "../sdk", version = "=1.8.5" } solana-transaction-status = { path = "../transaction-status", version = "=1.8.5" } diff --git a/cli/src/program.rs b/cli/src/program.rs index 2ff65641fa..d462562c40 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -9,7 +9,7 @@ use bip39::{Language, Mnemonic, MnemonicType, Seed}; use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; use log::*; use solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig}; -use solana_bpf_loader_program::{bpf_verifier, BpfError, ThisInstructionMeter}; +use solana_bpf_loader_program::{syscalls::register_syscalls, BpfError, ThisInstructionMeter}; use solana_clap_utils::{self, input_parsers::*, input_validators::*, keypair::*}; use solana_cli_output::{ CliProgram, CliProgramAccountType, CliProgramAuthority, CliProgramBuffer, CliProgramId, @@ -24,7 +24,10 @@ use solana_client::{ rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType}, tpu_client::{TpuClient, TpuClientConfig}, }; -use solana_rbpf::vm::{Config, Executable}; +use solana_rbpf::{ + verifier, + vm::{Config, Executable}, +}; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ account::Account, @@ -37,6 +40,7 @@ use solana_sdk::{ message::Message, native_token::Sol, packet::PACKET_DATA_SIZE, + process_instruction::MockInvokeContext, pubkey::Pubkey, signature::{keypair_from_seed, read_keypair_file, Keypair, Signature, Signer}, system_instruction::{self, SystemError}, @@ -1983,12 +1987,17 @@ fn read_and_verify_elf(program_location: &str) -> Result, Box>::from_elf( &program_data, - Some(|x| bpf_verifier::check(x)), - Config::default(), + Some(verifier::check), + Config { + reject_unresolved_syscalls: true, + ..Config::default() + }, + register_syscalls(&mut invoke_context).unwrap(), ) .map_err(|err| format!("ELF error: {}", err))?; diff --git a/cli/tests/fixtures/noop.so b/cli/tests/fixtures/noop.so index 17ea5290910bc7499fc260f32dd7c6554e8fa850..502681cf6e5f1b97b72def214afaaf144a2d1fb4 100755 GIT binary patch literal 1592 zcmb_c!EVz)5S_YBMJW=93KTe?R2&G0I*F4url+p%@M{t{Uostl-kmb$vhN9 zTjY|(-(_0LwI$yAs@p~Uq&$$W8Ny;%#Zr$zP_}XGRcbuH^F$b(&_A08jfAJ8# zKsOvU!$X%rdl-xT* R{`pQly}*A@{qO$8{}-1gbtwP< literal 4440 zcmb_fK}=j_5dOEc(poDOMUkZX;t8Adu^?=B@dCA)qT7m1No=Bl$G*qz3i}@HJ_0Xm zq8v1h@qmdY#FHGXc&x%b9?GBWn}5EU`Dgx_ zdH?_RlQ*+(9ZMvXj5hVRLaxEU2-EJTc>-iarBxd|Q{_XJ>~Z_+Ik!Vs#?5|2KP z!*AmW;!V0quo5bE#{fr@sdiE@>8&=xg`Ol<)t{$HH#q*CeIoK1#B%^6%8|Ursi^ie z4iG^ep=!^L<|o=P0>Y6BUN0c0R696CpOHhJyV{=Bcn!?-I_GKKiG;Zh;dMu=t9DRM z!nE3RPy3DIn8Iq$eT_#>S{t;(oTDg^i%(upNQY+ zHrHvL^4yiUssoEQs6KhF!;;kFThhZg{(7u9sGlSbTq(uCGOznB{6y>2$I&C| zCV7m<{cFqhIDfD&tmj>((QWEudEZK%r**!ien++657&0}dx3dvZ_!6he+%0Ek@ao# zBlSl+_j9yP{U&{O?nMX)#tHRvGrnw#_@W=^z0QNo0{uG2DS4FqMH`!Xol@r+TvpY% z7E5BcqG8qH5Pjr(>5`t*7tbw>_*@>J821D1uLg5OzCjSijbd)rDtN_wAskj0tZR#< zX|HSrGuAs^(O6~q zlgz)&l&?YNlzOmF>)&C0KAzQ<7&bK@K6whncrTgbIRIMWxZO^uaDxq+-v^M+ax@T>g#1h!S{$#E5Gbt-vNq)x1-X0{|JA};P(vvEZ|agCFOFiT-y6Kf(nO`F(@e8-aK+-MFVK9FOp827i+Mi`+8!4TIk^_$iK0?C%)- zIL9aQ9fSWg77tGE8~pn*e_C$v>6ky1uNi!A%%7GU{4$?E7$3^f9DnQvW|T)g;Rotv zi~cOUqgFP1*-G0chK0pxI~SDtpyM3hxiIHUSNi7WTpL8z^iVpJ zax-q~wSI3pGn8~Q{ex~gnaO0lWGa;#n3?fXGXn$et8thAn`3Q{t3UPG78hb)Bw#0U zM&tW}gU*G7T8(cE@E$FN)i`gOg~uz5OMeM|p79aRo8SYC?-=V0i$3RF^e-_!W#Df! zeg!ue8}I3PLaiBoZ!*4W=ua`Oi>l}J$TPlyMU0Ivael0=`9DBJK1^DjD-qzW&Y_h< zaAk+ya;WTbK$nRd`A(^rQ#MR0QHf|+R(9TBv`N)@xvPbE0alnv^kGYzx= zR|(CCD!iQFUb3?`NbLTk%3ivZoNUs5<_DM#GQG$&%``)l)dtvXh|m;~i|XMA>*VE| z*G8|7y&-vgT#DtzpOnAB3kuyb`bf@4@r$1SH=KzHHp7yCPG zFVrHl<}o1t8P<8jzhYv)%?d*0dqZA-v6ub74z`#Zv6t@wp}p)#>`gifa@>::from_elf(&elf, None, Config::default()) - .unwrap(); - executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + let mut executable = >::from_elf( + &elf, + None, + Config::default(), + register_syscalls(&mut invoke_context).unwrap(), + ) + .unwrap(); executable.jit_compile().unwrap(); let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; @@ -225,10 +229,13 @@ fn bench_create_vm(bencher: &mut Bencher) { .unwrap(); let elf = load_elf("noop").unwrap(); - let mut executable = - >::from_elf(&elf, None, Config::default()) - .unwrap(); - executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + let mut executable = >::from_elf( + &elf, + None, + Config::default(), + register_syscalls(&mut invoke_context).unwrap(), + ) + .unwrap(); bencher.iter(|| { let _ = create_vm( @@ -273,10 +280,13 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { .unwrap(); let elf = load_elf("tuner").unwrap(); - let mut executable = - >::from_elf(&elf, None, Config::default()) - .unwrap(); - executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + let executable = >::from_elf( + &elf, + None, + Config::default(), + register_syscalls(&mut invoke_context).unwrap(), + ) + .unwrap(); let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; let mut vm = create_vm( diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 853f85d163..e437449c34 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -211,14 +211,16 @@ fn run_program( let mut instruction_meter = ThisInstructionMeter { compute_meter }; let config = Config { - max_call_depth: 20, - stack_frame_size: 4096, - enable_instruction_meter: true, enable_instruction_tracing: true, + ..Config::default() }; - let mut executable = - >::from_elf(&data, None, config).unwrap(); - executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + let mut executable = >::from_elf( + &data, + None, + config, + register_syscalls(&mut invoke_context).unwrap(), + ) + .unwrap(); executable.jit_compile().unwrap(); let mut instruction_count = 0; diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index 03e076be19..0caca8d8a9 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -22,7 +22,7 @@ sha3 = "0.9.1" solana-measure = { path = "../../measure", version = "=1.8.5" } solana-runtime = { path = "../../runtime", version = "=1.8.5" } solana-sdk = { path = "../../sdk", version = "=1.8.5" } -solana_rbpf = "=0.2.11" +solana_rbpf = "=0.2.13" thiserror = "1.0" [dev-dependencies] diff --git a/programs/bpf_loader/src/bpf_verifier.rs b/programs/bpf_loader/src/bpf_verifier.rs deleted file mode 100644 index 57372262f5..0000000000 --- a/programs/bpf_loader/src/bpf_verifier.rs +++ /dev/null @@ -1,294 +0,0 @@ -#![allow(clippy::upper_case_acronyms)] - -use crate::BpfError; -use solana_rbpf::ebpf; -use thiserror::Error; - -/// Error definitions -#[derive(Debug, Error, PartialEq)] -pub enum VerifierError { - /// ProgramLengthNotMultiple - #[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)] - ProgramLengthNotMultiple, - /// ProgramTooLarge - #[error("program too big, max {}, is {}", ebpf::PROG_MAX_INSNS, .0)] - ProgramTooLarge(usize), - /// NoProgram - #[error("no program set, call prog_set() to load one")] - NoProgram, - #[error("division by 0 (insn #{0})")] - DivisionByZero(usize), - /// UnsupportedLEBEArgument - #[error("unsupported argument for LE/BE (insn #{0})")] - UnsupportedLEBEArgument(usize), - /// LDDWCannotBeLast - #[error("LD_DW instruction cannot be last in program")] - LDDWCannotBeLast, - /// IncompleteLDDW - #[error("incomplete LD_DW instruction (insn #{0})")] - IncompleteLDDW(usize), - /// InfiniteLoop - #[error("infinite loop (insn #{0})")] - InfiniteLoop(usize), - /// JumpOutOfCode - #[error("jump out of code to #{0} (insn #{1})")] - JumpOutOfCode(usize, usize), - /// JumpToMiddleOfLDDW - #[error("jump to middle of LD_DW at #{0} (insn #{1})")] - JumpToMiddleOfLDDW(usize, usize), - /// InvalidSourceRegister - #[error("invalid source register (insn #{0})")] - InvalidSourceRegister(usize), - /// CannotWriteR10 - #[error("cannot write into register r10 (insn #{0})")] - CannotWriteR10(usize), - /// InvalidDestinationRegister - #[error("invalid destination register (insn #{0})")] - InvalidDestinationRegister(usize), - /// UnknownOpCode - #[error("unknown eBPF opcode {0:#2x} (insn #{1:?})")] - UnknownOpCode(u8, usize), - /// Shift with overflow - #[error("Shift with overflow at instruction {0}")] - ShiftWithOverflow(usize), - /// Invalid register specified - #[error("Invalid register specified at instruction {0}")] - InvalidRegister(usize), -} - -fn adj_insn_ptr(insn_ptr: usize) -> usize { - insn_ptr + ebpf::ELF_INSN_DUMP_OFFSET -} - -fn check_prog_len(prog: &[u8]) -> Result<(), BpfError> { - if prog.len() % ebpf::INSN_SIZE != 0 { - return Err(VerifierError::ProgramLengthNotMultiple.into()); - } - if prog.is_empty() { - return Err(VerifierError::NoProgram.into()); - } - Ok(()) -} - -fn check_imm_nonzero(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), BpfError> { - if insn.imm == 0 { - return Err(VerifierError::DivisionByZero(adj_insn_ptr(insn_ptr)).into()); - } - Ok(()) -} - -fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), BpfError> { - match insn.imm { - 16 | 32 | 64 => Ok(()), - _ => Err(VerifierError::UnsupportedLEBEArgument(adj_insn_ptr(insn_ptr)).into()), - } -} - -fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), BpfError> { - if insn_ptr + 1 >= (prog.len() / ebpf::INSN_SIZE) { - // Last instruction cannot be LD_DW because there would be no 2nd DW - return Err(VerifierError::LDDWCannotBeLast.into()); - } - let next_insn = ebpf::get_insn(prog, insn_ptr + 1); - if next_insn.opc != 0 { - return Err(VerifierError::IncompleteLDDW(adj_insn_ptr(insn_ptr)).into()); - } - Ok(()) -} - -fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), BpfError> { - let insn = ebpf::get_insn(prog, insn_ptr); - // if insn.off == -1 { - // return Err(VerifierError::InfiniteLoop(adj_insn_ptr(insn_ptr)).into()); - // } - - let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize; - if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) { - return Err( - VerifierError::JumpOutOfCode(dst_insn_ptr as usize, adj_insn_ptr(insn_ptr)).into(), - ); - } - let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize); - if dst_insn.opc == 0 { - return Err(VerifierError::JumpToMiddleOfLDDW( - dst_insn_ptr as usize, - adj_insn_ptr(insn_ptr), - ) - .into()); - } - Ok(()) -} - -fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), BpfError> { - if insn.src > 10 { - return Err(VerifierError::InvalidSourceRegister(adj_insn_ptr(insn_ptr)).into()); - } - match (insn.dst, store) { - (0..=9, _) | (10, true) => Ok(()), - (10, false) => Err(VerifierError::CannotWriteR10(adj_insn_ptr(insn_ptr)).into()), - (_, _) => Err(VerifierError::InvalidDestinationRegister(adj_insn_ptr(insn_ptr)).into()), - } -} - -/// Check that the imm is a valid shift operand -fn check_imm_shift(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> { - if insn.imm < 0 || insn.imm as u64 >= 64 { - return Err(VerifierError::ShiftWithOverflow(adj_insn_ptr(insn_ptr))); - } - Ok(()) -} - -/// Check that the imm is a valid register number -fn check_imm_register(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> { - if insn.imm < 0 || insn.imm > 10 { - return Err(VerifierError::InvalidRegister(adj_insn_ptr(insn_ptr))); - } - Ok(()) -} - -#[rustfmt::skip] -pub fn check(prog: &[u8]) -> Result<(), BpfError> { - check_prog_len(prog)?; - - let mut insn_ptr: usize = 0; - while insn_ptr * ebpf::INSN_SIZE < prog.len() { - let insn = ebpf::get_insn(prog, insn_ptr); - let mut store = false; - - match insn.opc { - - // BPF_LD class - ebpf::LD_ABS_B => {}, - ebpf::LD_ABS_H => {}, - ebpf::LD_ABS_W => {}, - ebpf::LD_ABS_DW => {}, - ebpf::LD_IND_B => {}, - ebpf::LD_IND_H => {}, - ebpf::LD_IND_W => {}, - ebpf::LD_IND_DW => {}, - - ebpf::LD_DW_IMM => { - store = true; - check_load_dw(prog, insn_ptr)?; - insn_ptr += 1; - }, - - // BPF_LDX class - ebpf::LD_B_REG => {}, - ebpf::LD_H_REG => {}, - ebpf::LD_W_REG => {}, - ebpf::LD_DW_REG => {}, - - // BPF_ST class - ebpf::ST_B_IMM => store = true, - ebpf::ST_H_IMM => store = true, - ebpf::ST_W_IMM => store = true, - ebpf::ST_DW_IMM => store = true, - - // BPF_STX class - ebpf::ST_B_REG => store = true, - ebpf::ST_H_REG => store = true, - ebpf::ST_W_REG => store = true, - ebpf::ST_DW_REG => store = true, - - // BPF_ALU class - ebpf::ADD32_IMM => {}, - ebpf::ADD32_REG => {}, - ebpf::SUB32_IMM => {}, - ebpf::SUB32_REG => {}, - ebpf::MUL32_IMM => {}, - ebpf::MUL32_REG => {}, - ebpf::DIV32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, - ebpf::DIV32_REG => {}, - ebpf::OR32_IMM => {}, - ebpf::OR32_REG => {}, - ebpf::AND32_IMM => {}, - ebpf::AND32_REG => {}, - ebpf::LSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::LSH32_REG => {}, - ebpf::RSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::RSH32_REG => {}, - ebpf::NEG32 => {}, - ebpf::MOD32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, - ebpf::MOD32_REG => {}, - ebpf::XOR32_IMM => {}, - ebpf::XOR32_REG => {}, - ebpf::MOV32_IMM => {}, - ebpf::MOV32_REG => {}, - ebpf::ARSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::ARSH32_REG => {}, - ebpf::LE => { check_imm_endian(&insn, insn_ptr)?; }, - ebpf::BE => { check_imm_endian(&insn, insn_ptr)?; }, - - // BPF_ALU64 class - ebpf::ADD64_IMM => {}, - ebpf::ADD64_REG => {}, - ebpf::SUB64_IMM => {}, - ebpf::SUB64_REG => {}, - ebpf::MUL64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, - ebpf::MUL64_REG => {}, - ebpf::DIV64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, - ebpf::DIV64_REG => {}, - ebpf::OR64_IMM => {}, - ebpf::OR64_REG => {}, - ebpf::AND64_IMM => {}, - ebpf::AND64_REG => {}, - ebpf::LSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::LSH64_REG => {}, - ebpf::RSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::RSH64_REG => {}, - ebpf::NEG64 => {}, - ebpf::MOD64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, - ebpf::MOD64_REG => {}, - ebpf::XOR64_IMM => {}, - ebpf::XOR64_REG => {}, - ebpf::MOV64_IMM => {}, - ebpf::MOV64_REG => {}, - ebpf::ARSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; }, - ebpf::ARSH64_REG => {}, - - // BPF_JMP class - ebpf::JA => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JEQ_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JEQ_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JGT_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JGT_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JGE_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JGE_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JLT_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JLT_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JLE_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JLE_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSET_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSET_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JNE_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JNE_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSGT_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSGT_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSGE_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSGE_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSLT_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSLT_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSLE_IMM => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::JSLE_REG => { check_jmp_offset(prog, insn_ptr)?; }, - ebpf::CALL_IMM => {}, - ebpf::CALL_REG => { check_imm_register(&insn, insn_ptr)?; }, - ebpf::EXIT => {}, - - _ => { - return Err(VerifierError::UnknownOpCode(insn.opc, adj_insn_ptr(insn_ptr)).into()); - } - } - - check_registers(&insn, store, insn_ptr)?; - - insn_ptr += 1; - } - - // insn_ptr should now be equal to number of instructions. - if insn_ptr != prog.len() / ebpf::INSN_SIZE { - return Err(VerifierError::JumpOutOfCode(adj_insn_ptr(insn_ptr), adj_insn_ptr(insn_ptr)).into()); - } - - Ok(()) -} diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 3352c9d0f9..cc01f61d8f 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1,7 +1,6 @@ #![allow(clippy::integer_arithmetic)] pub mod alloc; pub mod allocator_bump; -pub mod bpf_verifier; pub mod deprecated; pub mod serialization; pub mod syscalls; @@ -10,7 +9,6 @@ pub mod upgradeable_with_jit; pub mod with_jit; use crate::{ - bpf_verifier::VerifierError, serialization::{deserialize_parameters, serialize_parameters}, syscalls::SyscallError, }; @@ -22,6 +20,7 @@ use solana_rbpf::{ error::{EbpfError, UserDefinedError}, memory_region::MemoryRegion, static_analysis::Analysis, + verifier::{self, VerifierError}, vm::{Config, EbpfVm, Executable, InstructionMeter}, }; use solana_runtime::message_processor::MessageProcessor; @@ -86,23 +85,27 @@ pub fn create_executor( let config = Config { max_call_depth: bpf_compute_budget.max_call_depth, stack_frame_size: bpf_compute_budget.stack_frame_size, - enable_instruction_meter: true, enable_instruction_tracing: log_enabled!(Trace), + ..Config::default() }; let mut executable = { let keyed_accounts = invoke_context.get_keyed_accounts()?; let program = keyed_account_at_index(keyed_accounts, program_account_index)?; let account = program.try_account_ref()?; let data = &account.data()[program_data_offset..]; - >::from_elf(data, None, config) + >::from_elf( + data, + None, + config, + syscall_registry, + ) } .map_err(|e| map_ebpf_error(invoke_context, e))?; let (_, elf_bytes) = executable .get_text_bytes() .map_err(|e| map_ebpf_error(invoke_context, e))?; - bpf_verifier::check(elf_bytes) - .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; - executable.set_syscall_registry(syscall_registry); + verifier::check(elf_bytes) + .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e.into())))?; if use_jit { if let Err(err) = executable.jit_compile() { ic_msg!(invoke_context, "Failed to compile program {:?}", err); @@ -1001,6 +1004,7 @@ impl Executor for BpfExecutor { mod tests { use super::*; use rand::Rng; + use solana_rbpf::vm::SyscallRegistry; use solana_runtime::{bank::Bank, bank_client::BankClient}; use solana_sdk::{ account::{ @@ -1054,9 +1058,10 @@ mod tests { solana_rbpf::elf::register_bpf_function(&mut bpf_functions, 0, "entrypoint").unwrap(); let program = >::from_text_bytes( program, - bpf_functions, None, Config::default(), + SyscallRegistry::default(), + bpf_functions, ) .unwrap(); let mut vm = @@ -1067,12 +1072,12 @@ mod tests { } #[test] - #[should_panic(expected = "VerifierError(LDDWCannotBeLast)")] + #[should_panic(expected = "LDDWCannotBeLast")] fn test_bpf_loader_check_load_dw() { let prog = &[ 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // first half of lddw ]; - bpf_verifier::check(prog).unwrap(); + verifier::check(prog).unwrap(); } #[test] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 0bc3e3f5f1..409899b7f7 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2764,13 +2764,6 @@ mod tests { }; use std::str::FromStr; - const DEFAULT_CONFIG: Config = Config { - max_call_depth: 20, - stack_frame_size: 4_096, - enable_instruction_meter: true, - enable_instruction_tracing: false, - }; - macro_rules! assert_access_violation { ($result:expr, $va:expr, $len:expr) => { match $result { @@ -2792,9 +2785,10 @@ mod tests { const LENGTH: u64 = 1000; let data = vec![0u8; LENGTH as usize]; let addr = data.as_ptr() as u64; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice(&data, START, 0, false)], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -2831,6 +2825,7 @@ mod tests { // Pubkey let pubkey = solana_sdk::pubkey::new_rand(); let addr = &pubkey as *const _ as u64; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -2839,7 +2834,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_pubkey = @@ -2861,7 +2856,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_instruction = @@ -2880,6 +2875,7 @@ mod tests { let data: Vec = vec![]; assert_eq!(0x1 as *const u8, data.as_ptr()); let addr = good_data.as_ptr() as *const _ as u64; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -2888,7 +2884,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_data = translate_slice::( @@ -2913,7 +2909,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_data = translate_slice::( @@ -2956,7 +2952,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_data = translate_slice::( @@ -2986,7 +2982,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let translated_data = translate_slice::( @@ -3006,6 +3002,7 @@ mod tests { fn test_translate_string_and_do() { let string = "Gaggablaghblagh!"; let addr = string.as_ptr() as *const _ as u64; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -3014,7 +3011,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); assert_eq!( @@ -3037,9 +3034,9 @@ mod tests { #[test] #[should_panic(expected = "UserError(SyscallError(Abort))")] fn test_syscall_abort() { + let config = Config::default(); let memory_mapping = - MemoryMapping::new::(vec![MemoryRegion::default()], &DEFAULT_CONFIG) - .unwrap(); + MemoryMapping::new::(vec![MemoryRegion::default()], &config).unwrap(); let mut result: Result> = Ok(0); SyscallAbort::call( &mut SyscallAbort {}, @@ -3059,6 +3056,7 @@ mod tests { fn test_syscall_sol_panic() { let string = "Gaggablaghblagh!"; let addr = string.as_ptr() as *const _ as u64; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -3067,7 +3065,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3135,6 +3133,7 @@ mod tests { loader_id: &bpf_loader::id(), enforce_aligned_host_addrs: true, }; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -3143,7 +3142,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3248,7 +3247,8 @@ mod tests { compute_meter, logger, }; - let memory_mapping = MemoryMapping::new::(vec![], &DEFAULT_CONFIG).unwrap(); + let config = Config::default(); + let memory_mapping = MemoryMapping::new::(vec![], &config).unwrap(); let mut result: Result> = Ok(0); syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); @@ -3275,6 +3275,7 @@ mod tests { loader_id: &bpf_loader::id(), enforce_aligned_host_addrs: true, }; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion { host_addr: addr, @@ -3283,7 +3284,7 @@ mod tests { vm_gap_shift: 63, is_writable: false, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3318,6 +3319,7 @@ mod tests { #[test] fn test_syscall_sol_alloc_free() { + let config = Config::default(); // large alloc { let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); @@ -3328,7 +3330,7 @@ mod tests { 0, true, )], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let mut syscall = SyscallAllocFree { @@ -3355,7 +3357,7 @@ mod tests { 0, true, )], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let mut syscall = SyscallAllocFree { @@ -3381,7 +3383,7 @@ mod tests { 0, true, )], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let mut syscall = SyscallAllocFree { @@ -3401,6 +3403,7 @@ mod tests { fn check_alignment() { let heap = AlignedMemory::new_with_size(100, HOST_ALIGN); + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![MemoryRegion::new_from_slice( heap.as_slice(), @@ -3408,7 +3411,7 @@ mod tests { 0, true, )], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let mut syscall = SyscallAllocFree { @@ -3454,6 +3457,7 @@ mod tests { let ro_len = bytes_to_hash.len() as u64; let ro_va = 96; let rw_va = 192; + let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion { @@ -3485,7 +3489,7 @@ mod tests { is_writable: true, }, ], - &DEFAULT_CONFIG, + &config, ) .unwrap(); let compute_meter: Rc> = @@ -3551,6 +3555,7 @@ mod tests { #[test] fn test_syscall_get_sysvar() { + let config = Config::default(); // Test clock sysvar { let got_clock = Clock::default(); @@ -3564,7 +3569,7 @@ mod tests { vm_gap_shift: 63, is_writable: true, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3606,7 +3611,7 @@ mod tests { vm_gap_shift: 63, is_writable: true, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3656,7 +3661,7 @@ mod tests { vm_gap_shift: 63, is_writable: true, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); @@ -3696,7 +3701,7 @@ mod tests { vm_gap_shift: 63, is_writable: true, }], - &DEFAULT_CONFIG, + &config, ) .unwrap(); diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index 0a98d59663..39ba349bdd 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -185,14 +185,21 @@ native machine code before execting it in the virtual machine.", file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); + let syscall_registry = register_syscalls(&mut invoke_context).unwrap(); let mut executable = if magic == [0x7f, 0x45, 0x4c, 0x46] { - >::from_elf(&contents, None, config) - .map_err(|err| format!("Executable constructor failed: {:?}", err)) + >::from_elf( + &contents, + None, + config, + syscall_registry, + ) + .map_err(|err| format!("Executable constructor failed: {:?}", err)) } else { assemble::( std::str::from_utf8(contents.as_slice()).unwrap(), None, config, + syscall_registry, ) } .unwrap(); @@ -201,7 +208,6 @@ native machine code before execting it in the virtual machine.", let (_, elf_bytes) = executable.get_text_bytes().unwrap(); check(elf_bytes).unwrap(); } - executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); executable.jit_compile().unwrap(); let analysis = Analysis::from_executable(executable.as_ref());