From 49a715ddd6e480d95a081c29cca2ad3e47f9dc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 16 Jun 2021 17:27:10 +0200 Subject: [PATCH] Configurable enforcement of syscalls to be resolved when an ELF file is loaded. --- src/elf.rs | 20 +++++++++++++++++--- src/vm.rs | 3 +++ tests/ubpf_execution.rs | 21 +++++++++++---------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/elf.rs b/src/elf.rs index 256f6c8c3..502598202 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -359,7 +359,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EBpfElf { pub fn load( config: Config, bytes: &[u8], - syscall_registry: SyscallRegistry, + mut syscall_registry: SyscallRegistry, ) -> Result { let elf = Elf::parse(bytes)?; let mut elf_bytes = AlignedMemory::new_with_data(bytes, ebpf::HOST_ALIGN); @@ -385,8 +385,10 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EBpfElf { let mut bpf_functions = BTreeMap::default(); let mut syscall_symbols = BTreeMap::default(); Self::relocate( + &config, &mut bpf_functions, &mut syscall_symbols, + &mut syscall_registry, &elf, elf_bytes.as_slice_mut(), )?; @@ -539,8 +541,10 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EBpfElf { /// Relocates the ELF in-place fn relocate( + config: &Config, bpf_functions: &mut BTreeMap, syscall_symbols: &mut BTreeMap, + syscall_registry: &mut SyscallRegistry, elf: &Elf, elf_bytes: &mut [u8], ) -> Result<(), ElfError> { @@ -635,10 +639,20 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EBpfElf { register_bpf_function(bpf_functions, target_pc, name)? } else { // syscall - syscall_cache + let hash = syscall_cache .entry(sym.st_name) .or_insert_with(|| (ebpf::hash_symbol_name(name.as_bytes()), name)) - .0 + .0; + if config.reject_unresolved_syscalls + && syscall_registry.lookup_syscall(hash).is_none() + { + return Err(ElfError::UnresolvedSymbol( + name.to_string(), + r_offset / ebpf::INSN_SIZE + ebpf::ELF_INSN_DUMP_OFFSET, + r_offset, + )); + } + hash }; let mut checked_slice = elf_bytes .get_mut(imm_offset..imm_offset.saturating_add(BYTE_LENGTH_IMMEIDATE)) diff --git a/src/vm.rs b/src/vm.rs index 50cb0e26d..a25378c65 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -183,6 +183,8 @@ pub struct Config { pub enable_instruction_meter: bool, /// Enable instruction tracing pub enable_instruction_tracing: bool, + /// Reject ELF files containing syscalls which are not in the SyscallRegistry + pub reject_unresolved_syscalls: bool, /// Ratio of random no-ops per instruction in JIT (0.0 = OFF) pub noop_instruction_ratio: f64, /// Enable disinfection of immediate values and offsets provided by the user in JIT @@ -197,6 +199,7 @@ impl Default for Config { stack_frame_size: 4_096, enable_instruction_meter: true, enable_instruction_tracing: false, + reject_unresolved_syscalls: false, noop_instruction_ratio: 1.0 / 256.0, sanitize_user_provided_values: true, encrypt_environment_registers: true, diff --git a/tests/ubpf_execution.rs b/tests/ubpf_execution.rs index 503ac3a51..74d8a6ecc 100644 --- a/tests/ubpf_execution.rs +++ b/tests/ubpf_execution.rs @@ -3054,16 +3054,17 @@ fn test_err_call_unresolved() { #[test] fn test_err_unresolved_elf() { - test_interpreter_and_jit_elf!( - "tests/elfs/unresolved_syscall.so", - [], - ( - b"log" => syscalls::BpfSyscallString::call; syscalls::BpfSyscallString {}, - ), - { - |_vm, res: Result| matches!(res.unwrap_err(), EbpfError::ElfError(ElfError::UnresolvedSymbol(symbol, pc, offset)) if symbol == "log_64" && pc == 550 && offset == 4168) - }, - 9 + let mut syscall_registry = SyscallRegistry::default(); + test_interpreter_and_jit!(register, syscall_registry, b"log" => syscalls::BpfSyscallString::call; syscalls::BpfSyscallString {}); + let mut file = File::open("tests/elfs/unresolved_syscall.so").unwrap(); + let mut elf = Vec::new(); + file.read_to_end(&mut elf).unwrap(); + let config = Config { + reject_unresolved_syscalls: true, + ..Default::default() + }; + assert!( + matches!(>::from_elf(&elf, None, config, syscall_registry), Err(EbpfError::ElfError(ElfError::UnresolvedSymbol(symbol, pc, offset))) if symbol == "log_64" && pc == 550 && offset == 4168) ); }