From 99d559198c00ab7b6dd7089ca33d00bde5231c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 19 Jul 2021 14:04:10 +0200 Subject: [PATCH] Make Verifier Restriction on MUL64_IMM Configurable (#201) * Passes the config to the executable verifier. * Adds the "verify_mul64_imm_nonzero" config flag. --- src/verifier.rs | 10 +++++++--- src/vm.rs | 11 +++++++---- tests/ubpf_verifier.rs | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/verifier.rs b/src/verifier.rs index bfffbeec7..12428e400 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -21,7 +21,7 @@ //! //! Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all. -use crate::ebpf; +use crate::{ebpf, vm::Config}; use thiserror::Error; /// Error definitions @@ -173,7 +173,7 @@ fn check_imm_register(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Verifier /// Check the program against the verifier's rules #[rustfmt::skip] -pub fn check(prog: &[u8]) -> Result<(), VerifierError> { +pub fn check(prog: &[u8], config: &Config) -> Result<(), VerifierError> { check_prog_len(prog)?; let mut insn_ptr: usize = 0; @@ -250,7 +250,11 @@ pub fn check(prog: &[u8]) -> Result<(), VerifierError> { ebpf::ADD64_REG => {}, ebpf::SUB64_IMM => {}, ebpf::SUB64_REG => {}, - ebpf::MUL64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, + ebpf::MUL64_IMM => { + if config.verify_mul64_imm_nonzero { + check_imm_nonzero(&insn, insn_ptr)?; + } + }, ebpf::MUL64_REG => {}, ebpf::DIV64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; }, ebpf::DIV64_REG => {}, diff --git a/src/vm.rs b/src/vm.rs index 1862a40d7..05b018b9c 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -37,7 +37,7 @@ use std::{ /// - Unknown instructions. /// - Bad formed instruction. /// - Unknown eBPF syscall index. -pub type Verifier = fn(prog: &[u8]) -> Result<(), VerifierError>; +pub type Verifier = fn(prog: &[u8], config: &Config) -> Result<(), VerifierError>; /// Return value of programs and syscalls pub type ProgramResult = Result>; @@ -193,6 +193,8 @@ pub struct Config { pub sanitize_user_provided_values: bool, /// Encrypt the environment registers in JIT pub encrypt_environment_registers: bool, + /// Feature flag for the MUL64_IMM != 0 verification check + pub verify_mul64_imm_nonzero: bool, } impl Default for Config { fn default() -> Self { @@ -206,6 +208,7 @@ impl Default for Config { noop_instruction_ratio: 1.0 / 256.0, sanitize_user_provided_values: true, encrypt_environment_registers: true, + verify_mul64_imm_nonzero: false, } } } @@ -252,9 +255,9 @@ impl dyn Executable { syscall_registry: SyscallRegistry, ) -> Result, EbpfError> { let ebpf_elf = EBpfElf::load(config, elf_bytes, syscall_registry)?; - let (_, bytes) = ebpf_elf.get_text_bytes()?; + let text_bytes = ebpf_elf.get_text_bytes()?.1; if let Some(verifier) = verifier { - verifier(bytes)?; + verifier(text_bytes, &config)?; } Ok(Box::new(ebpf_elf)) } @@ -267,7 +270,7 @@ impl dyn Executable { bpf_functions: BTreeMap, ) -> Result, EbpfError> { if let Some(verifier) = verifier { - verifier(text_bytes).map_err(EbpfError::VerifierError)?; + verifier(text_bytes, &config).map_err(EbpfError::VerifierError)?; } Ok(Box::new(EBpfElf::new_from_text_bytes( config, diff --git a/tests/ubpf_verifier.rs b/tests/ubpf_verifier.rs index 6c0c9194b..a4414aec2 100644 --- a/tests/ubpf_verifier.rs +++ b/tests/ubpf_verifier.rs @@ -46,7 +46,7 @@ fn test_verifier_success() { " mov32 r0, 0xBEE exit", - Some(|_prog: &[u8]| Ok(())), + Some(|_prog: &[u8], _config: &Config| Ok(())), Config::default(), SyscallRegistry::default(), ) @@ -58,7 +58,7 @@ fn test_verifier_success() { #[test] #[should_panic(expected = "NoProgram")] fn test_verifier_fail() { - fn verifier_fail(_prog: &[u8]) -> Result<(), VerifierError> { + fn verifier_fail(_prog: &[u8], _config: &Config) -> Result<(), VerifierError> { Err(VerifierError::NoProgram) } let _executable = assemble::(