From 7ef5c4e910c9c075d95fc8ac4386658809e40577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 3 Jul 2024 19:50:04 +0200 Subject: [PATCH] Cleanup - old Goblin ELF parser * Removes the dependency "goblin". * Removes the adapter traits. * Inlines the trivial implementations and such that have only one call site. Moves the rest to other files. * Dissolves NewParser. * Removes std::borrow::Cow. --- Cargo.lock | 32 --- Cargo.toml | 1 - cli/Cargo.lock | 32 --- fuzz/Cargo.lock | 61 ++--- src/elf.rs | 275 ++++++++++---------- src/elf_parser/mod.rs | 47 ++++ src/elf_parser_glue.rs | 566 ----------------------------------------- src/lib.rs | 1 - src/vm.rs | 3 - test_utils/Cargo.lock | 55 ++-- 10 files changed, 232 insertions(+), 841 deletions(-) delete mode 100644 src/elf_parser_glue.rs diff --git a/Cargo.lock b/Cargo.lock index 5ed4c3c3..d65654c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,17 +155,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "goblin" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c955ab4e0ad8c843ea653a3d143048b87490d9be56bd7132a435c2407846ac8f" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "hash32" version = "0.2.1" @@ -244,12 +233,6 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -342,20 +325,6 @@ name = "scroll" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "shuttle" @@ -391,7 +360,6 @@ dependencies = [ "combine", "elf", "gdbstub", - "goblin", "hash32", "json", "libc", diff --git a/Cargo.toml b/Cargo.toml index f865f90b..6d3ad610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ arbitrary = { version = "1.0", optional = true, features = ["derive"] } byteorder = "1.2" combine = "3.8.1" gdbstub = { version = "0.6.2", optional = true } -goblin = "0.5.1" hash32 = "0.2.0" log = "0.4.2" rand = { version = "0.8.5", features = ["small_rng"]} diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 9f0c2199..0956ff0f 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -125,17 +125,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "goblin" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c955ab4e0ad8c843ea653a3d143048b87490d9be56bd7132a435c2407846ac8f" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "hash32" version = "0.2.1" @@ -233,12 +222,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -337,20 +320,6 @@ name = "scroll" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "solana_rbpf" @@ -359,7 +328,6 @@ dependencies = [ "byteorder", "combine", "gdbstub", - "goblin", "hash32", "libc", "log", diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index c4d0d196..9db26858 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -127,17 +127,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "goblin" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c955ab4e0ad8c843ea653a3d143048b87490d9be56bd7132a435c2407846ac8f" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "hash32" version = "0.2.1" @@ -228,12 +217,6 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -330,29 +313,14 @@ name = "scroll" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "solana_rbpf" -version = "0.4.0" +version = "0.8.1" dependencies = [ "arbitrary", "byteorder", "combine", - "goblin", "hash32", "libc", "log", @@ -360,11 +328,12 @@ dependencies = [ "rustc-demangle", "scroll", "thiserror", + "winapi", ] [[package]] name = "solana_rbpf-fuzz" -version = "0.4.0" +version = "0.8.1" dependencies = [ "arbitrary", "libfuzzer-sys", @@ -387,7 +356,7 @@ dependencies = [ [[package]] name = "test_utils" -version = "0.4.0" +version = "0.8.1" dependencies = [ "libc", "solana_rbpf", @@ -439,3 +408,25 @@ name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/src/elf.rs b/src/elf.rs index e8813ea8..220663f5 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -14,11 +14,8 @@ use crate::{ ELFCLASS64, ELFDATA2LSB, ELFOSABI_NONE, EM_BPF, EM_SBPF, ET_DYN, R_X86_64_32, R_X86_64_64, R_X86_64_NONE, R_X86_64_RELATIVE, }, - types::Elf64Word, - }, - elf_parser_glue::{ - ElfParser, ElfProgramHeader, ElfRelocation, ElfSectionHeader, ElfSymbol, GoblinParser, - NewParser, + types::{Elf64Phdr, Elf64Shdr, Elf64Word}, + Elf64, ElfParserError, }, error::EbpfError, memory_region::MemoryRegion, @@ -112,6 +109,42 @@ pub enum ElfError { InvalidProgramHeader, } +impl From for ElfError { + fn from(err: ElfParserError) -> Self { + match err { + ElfParserError::InvalidSectionHeader + | ElfParserError::InvalidString + | ElfParserError::InvalidSize + | ElfParserError::Overlap + | ElfParserError::SectionNotInOrder + | ElfParserError::NoSectionNameStringTable + | ElfParserError::InvalidDynamicSectionTable + | ElfParserError::InvalidRelocationTable + | ElfParserError::InvalidAlignment + | ElfParserError::NoStringTable + | ElfParserError::NoDynamicStringTable + | ElfParserError::InvalidFileHeader + | ElfParserError::StringTooLong(_, _) => ElfError::FailedToParse(err.to_string()), + ElfParserError::InvalidProgramHeader => ElfError::InvalidProgramHeader, + ElfParserError::OutOfBounds => ElfError::ValueOutOfBounds, + } + } +} + +fn get_section(elf: &Elf64, name: &[u8]) -> Result { + for section_header in elf.section_header_table() { + if elf.section_name(section_header.sh_name)? == name { + return Ok(section_header.clone()); + } + } + + Err(ElfError::SectionNotFound( + std::str::from_utf8(name) + .unwrap_or("UTF-8 error") + .to_string(), + )) +} + // For more information on the BPF instruction set: // https://github.com/iovisor/bpf-docs/blob/master/eBPF.md @@ -365,31 +398,27 @@ impl Executable { /// Fully loads an ELF, including validation and relocation pub fn load(bytes: &[u8], loader: Arc>) -> Result { - if loader.get_config().new_elf_parser { - // The new parser creates references from the input byte slice, so - // it must be properly aligned. We assume that HOST_ALIGN is a - // multiple of the ELF "natural" alignment. See test_load_unaligned. - let aligned; - let bytes = if is_memory_aligned(bytes.as_ptr() as usize, HOST_ALIGN) { - bytes - } else { - aligned = AlignedMemory::<{ HOST_ALIGN }>::from_slice(bytes); - aligned.as_slice() - }; - Self::load_with_parser(&NewParser::parse(bytes)?, bytes, loader) + // The new parser creates references from the input byte slice, so + // it must be properly aligned. We assume that HOST_ALIGN is a + // multiple of the ELF "natural" alignment. See test_load_unaligned. + let aligned; + let bytes = if is_memory_aligned(bytes.as_ptr() as usize, HOST_ALIGN) { + bytes } else { - Self::load_with_parser(&GoblinParser::parse(bytes)?, bytes, loader) - } + aligned = AlignedMemory::<{ HOST_ALIGN }>::from_slice(bytes); + aligned.as_slice() + }; + Self::load_with_parser(&Elf64::parse(bytes)?, bytes, loader) } - fn load_with_parser<'a, P: ElfParser<'a>>( - elf: &'a P, + fn load_with_parser( + elf: &Elf64, bytes: &[u8], loader: Arc>, ) -> Result { let mut elf_bytes = AlignedMemory::from_slice(bytes); let config = loader.get_config(); - let header = elf.header(); + let header = elf.file_header(); let sbpf_version = if header.e_flags == EF_SBPF_V2 { SBPFVersion::V2 } else { @@ -399,10 +428,11 @@ impl Executable { Self::validate(config, elf, elf_bytes.as_slice())?; // calculate the text section info - let text_section = elf.section(b".text")?; + let text_section = get_section(elf, b".text")?; let text_section_info = SectionInfo { name: if config.enable_symbol_and_section_labels { - elf.section_name(text_section.sh_name()) + elf.section_name(text_section.sh_name) + .ok() .and_then(|name| std::str::from_utf8(name).ok()) .unwrap_or(".text") .to_string() @@ -410,26 +440,22 @@ impl Executable { String::default() }, vaddr: if sbpf_version.enable_elf_vaddr() - && text_section.sh_addr() >= ebpf::MM_PROGRAM_START + && text_section.sh_addr >= ebpf::MM_PROGRAM_START { - text_section.sh_addr() + text_section.sh_addr } else { - text_section - .sh_addr() - .saturating_add(ebpf::MM_PROGRAM_START) + text_section.sh_addr.saturating_add(ebpf::MM_PROGRAM_START) }, offset_range: text_section.file_range().unwrap_or_default(), }; let vaddr_end = if sbpf_version.reject_rodata_stack_overlap() { - text_section_info - .vaddr - .saturating_add(text_section.sh_size()) + text_section_info.vaddr.saturating_add(text_section.sh_size) } else { text_section_info.vaddr }; if (config.reject_broken_elfs && !sbpf_version.enable_elf_vaddr() - && text_section.sh_addr() != text_section.sh_offset()) + && text_section.sh_addr != text_section.sh_offset) || vaddr_end > ebpf::MM_STACK_START { return Err(ElfError::ValueOutOfBounds); @@ -445,7 +471,7 @@ impl Executable { )?; // calculate entrypoint offset into the text section - let offset = header.e_entry.saturating_sub(text_section.sh_addr()); + let offset = header.e_entry.saturating_sub(text_section.sh_addr); if offset.checked_rem(ebpf::INSN_SIZE as u64) != Some(0) { return Err(ElfError::InvalidEntrypoint); } @@ -467,8 +493,9 @@ impl Executable { let ro_section = Self::parse_ro_sections( config, &sbpf_version, - elf.section_headers() - .map(|s| (elf.section_name(s.sh_name()), s)), + elf.section_header_table() + .iter() + .map(|s| (elf.section_name(s.sh_name).ok(), s)), elf_bytes.as_slice(), )?; @@ -515,12 +542,8 @@ impl Executable { // Functions exposed for tests /// Validates the ELF - pub fn validate<'a, P: ElfParser<'a>>( - config: &Config, - elf: &'a P, - elf_bytes: &[u8], - ) -> Result<(), ElfError> { - let header = elf.header(); + pub fn validate(config: &Config, elf: &Elf64, elf_bytes: &[u8]) -> Result<(), ElfError> { + let header = elf.file_header(); if header.e_ident.ei_class != ELFCLASS64 { return Err(ElfError::WrongClass); } @@ -530,7 +553,7 @@ impl Executable { if header.e_ident.ei_osabi != ELFOSABI_NONE { return Err(ElfError::WrongAbi); } - if header.e_machine != EM_BPF && (!config.new_elf_parser || header.e_machine != EM_SBPF) { + if header.e_machine != EM_BPF && header.e_machine != EM_SBPF { return Err(ElfError::WrongMachine); } if header.e_type != ET_DYN { @@ -557,45 +580,33 @@ impl Executable { return Err(ElfError::UnsupportedSBPFVersion); } - // This is needed to avoid an overflow error in header.vm_range() as - // used by relocate(). See https://github.com/m4b/goblin/pull/306. - // - // Once we bump to a version of goblin that includes the fix, this - // check can be removed, and relocate() will still return - // ValueOutOfBounds on malformed program headers. - if elf - .program_headers() - .any(|header| header.p_vaddr().checked_add(header.p_memsz()).is_none()) - { - return Err(ElfError::InvalidProgramHeader); - } - // The toolchain currently emits up to 4 program headers. 10 is a // future proof nice round number. // // program_headers() returns an ExactSizeIterator so count doesn't // actually iterate again. - if elf.program_headers().count() >= 10 { + if elf.program_header_table().iter().count() >= 10 { return Err(ElfError::InvalidProgramHeader); } } - let num_text_sections = elf - .section_headers() - .fold(0, |count: usize, section_header| { - if let Some(this_name) = elf.section_name(section_header.sh_name()) { - if this_name == b".text" { - return count.saturating_add(1); + let num_text_sections = + elf.section_header_table() + .iter() + .fold(0, |count: usize, section_header| { + if let Ok(this_name) = elf.section_name(section_header.sh_name) { + if this_name == b".text" { + return count.saturating_add(1); + } } - } - count - }); + count + }); if 1 != num_text_sections { return Err(ElfError::NotOneTextSection); } - for section_header in elf.section_headers() { - if let Some(name) = elf.section_name(section_header.sh_name()) { + for section_header in elf.section_header_table().iter() { + if let Ok(name) = elf.section_name(section_header.sh_name) { if name.starts_with(b".bss") || (section_header.is_writable() && (name.starts_with(b".data") && !name.starts_with(b".data.rel"))) @@ -607,17 +618,17 @@ impl Executable { } } - for section_header in elf.section_headers() { - let start = section_header.sh_offset() as usize; + for section_header in elf.section_header_table().iter() { + let start = section_header.sh_offset as usize; let end = section_header - .sh_offset() - .checked_add(section_header.sh_size()) + .sh_offset + .checked_add(section_header.sh_size) .ok_or(ElfError::ValueOutOfBounds)? as usize; let _ = elf_bytes .get(start..end) .ok_or(ElfError::ValueOutOfBounds)?; } - let text_section = elf.section(b".text")?; + let text_section = get_section(elf, b".text")?; if !text_section.vm_range().contains(&header.e_entry) { return Err(ElfError::EntrypointOutOfBounds); } @@ -627,8 +638,7 @@ impl Executable { pub(crate) fn parse_ro_sections< 'a, - T: ElfSectionHeader + 'a, - S: IntoIterator, &'a T)>, + S: IntoIterator, &'a Elf64Shdr)>, >( config: &Config, sbpf_version: &SBPFVersion, @@ -670,7 +680,7 @@ impl Executable { last_ro_section = i; n_ro_sections = n_ro_sections.saturating_add(1); - let section_addr = section_header.sh_addr(); + let section_addr = section_header.sh_addr; // sh_offset handling: // @@ -686,10 +696,10 @@ impl Executable { if sbpf_version.enable_elf_vaddr() { // This is enforced in validate() debug_assert!(config.optimize_rodata); - if section_addr < section_header.sh_offset() { + if section_addr < section_header.sh_offset { invalid_offsets = true; } else { - let offset = section_addr.saturating_sub(section_header.sh_offset()); + let offset = section_addr.saturating_sub(section_header.sh_offset); if *addr_file_offset.get_or_insert(offset) != offset { // The sections are not all translated by the same // constant. We won't be able to borrow, but unless @@ -698,7 +708,7 @@ impl Executable { invalid_offsets = true; } } - } else if section_addr != section_header.sh_offset() { + } else if section_addr != section_header.sh_offset { invalid_offsets = true; } } @@ -710,7 +720,7 @@ impl Executable { section_addr.saturating_add(ebpf::MM_PROGRAM_START) }; if sbpf_version.reject_rodata_stack_overlap() { - vaddr_end = vaddr_end.saturating_add(section_header.sh_size()); + vaddr_end = vaddr_end.saturating_add(section_header.sh_size); } if (config.reject_broken_elfs && invalid_offsets) || vaddr_end > ebpf::MM_STACK_START { return Err(ElfError::ValueOutOfBounds); @@ -807,15 +817,15 @@ impl Executable { } /// Relocates the ELF in-place - fn relocate<'a, P: ElfParser<'a>>( + fn relocate( function_registry: &mut FunctionRegistry, loader: &BuiltinProgram, - elf: &'a P, + elf: &Elf64, elf_bytes: &mut [u8], ) -> Result<(), ElfError> { let mut syscall_cache = BTreeMap::new(); - let text_section = elf.section(b".text")?; - let sbpf_version = if elf.header().e_flags == EF_SBPF_V2 { + let text_section = get_section(elf, b".text")?; + let sbpf_version = if elf.file_header().e_flags == EF_SBPF_V2 { SBPFVersion::V2 } else { SBPFVersion::V1 @@ -861,11 +871,11 @@ impl Executable { } } - let mut program_header: Option<&

>::ProgramHeader> = None; + let mut program_header: Option<&Elf64Phdr> = None; // Fixup all the relocations in the relocation section if exists - for relocation in elf.dynamic_relocations() { - let mut r_offset = relocation.r_offset() as usize; + for relocation in elf.dynamic_relocations_table().unwrap_or_default().iter() { + let mut r_offset = relocation.r_offset as usize; // When sbpf_version.enable_elf_vaddr()=true, we allow section.sh_addr != // section.sh_offset so we need to bring r_offset to the correct @@ -875,14 +885,15 @@ impl Executable { Some(header) if header.vm_range().contains(&(r_offset as u64)) => {} _ => { program_header = elf - .program_headers() + .program_header_table() + .iter() .find(|header| header.vm_range().contains(&(r_offset as u64))) } } let header = program_header.as_ref().ok_or(ElfError::ValueOutOfBounds)?; r_offset = r_offset - .saturating_sub(header.p_vaddr() as usize) - .saturating_add(header.p_offset() as usize); + .saturating_sub(header.p_vaddr as usize) + .saturating_add(header.p_offset as usize); } match BpfRelocationType::from_x86_relocation_type(relocation.r_type()) { @@ -907,12 +918,13 @@ impl Executable { let refd_addr = LittleEndian::read_u32(checked_slice) as u64; let symbol = elf - .dynamic_symbol(relocation.r_sym()) + .dynamic_symbol_table() + .and_then(|table| table.get(relocation.r_sym() as usize).cloned()) .ok_or_else(|| ElfError::UnknownSymbol(relocation.r_sym() as usize))?; // The relocated address is relative to the address of the // symbol at index `r_sym` - let mut addr = symbol.st_value().saturating_add(refd_addr); + let mut addr = symbol.st_value.saturating_add(refd_addr); // The "physical address" from the VM's perspective is rooted // at `MM_PROGRAM_START`. If the linker hasn't already put @@ -1073,19 +1085,20 @@ impl Executable { let imm_offset = r_offset.saturating_add(BYTE_OFFSET_IMMEDIATE); let symbol = elf - .dynamic_symbol(relocation.r_sym()) + .dynamic_symbol_table() + .and_then(|table| table.get(relocation.r_sym() as usize).cloned()) .ok_or_else(|| ElfError::UnknownSymbol(relocation.r_sym() as usize))?; let name = elf - .dynamic_symbol_name(symbol.st_name() as Elf64Word) - .ok_or_else(|| ElfError::UnknownSymbol(symbol.st_name() as usize))?; + .dynamic_symbol_name(symbol.st_name as Elf64Word) + .map_err(|_| ElfError::UnknownSymbol(symbol.st_name as usize))?; // If the symbol is defined, this is a bpf-to-bpf call - let key = if symbol.is_function() && symbol.st_value() != 0 { - if !text_section.vm_range().contains(&symbol.st_value()) { + let key = if symbol.is_function() && symbol.st_value != 0 { + if !text_section.vm_range().contains(&symbol.st_value) { return Err(ElfError::ValueOutOfBounds); } - let target_pc = (symbol.st_value().saturating_sub(text_section.sh_addr()) + let target_pc = (symbol.st_value.saturating_sub(text_section.sh_addr) as usize) .checked_div(ebpf::INSN_SIZE) .unwrap_or_default(); @@ -1098,7 +1111,7 @@ impl Executable { } else { // Else it's a syscall let hash = *syscall_cache - .entry(symbol.st_name()) + .entry(symbol.st_name) .or_insert_with(|| ebpf::hash_symbol_name(name)); if config.reject_broken_elfs && loader.get_function_registry().lookup_by_key(hash).is_none() @@ -1123,19 +1136,19 @@ impl Executable { if config.enable_symbol_and_section_labels { // Register all known function names from the symbol table - for symbol in elf.symbols() { - if symbol.st_info() & 0xEF != 0x02 { + for symbol in elf.symbol_table().ok().flatten().unwrap_or_default().iter() { + if symbol.st_info & 0xEF != 0x02 { continue; } - if !text_section.vm_range().contains(&symbol.st_value()) { + if !text_section.vm_range().contains(&symbol.st_value) { return Err(ElfError::ValueOutOfBounds); } - let target_pc = (symbol.st_value().saturating_sub(text_section.sh_addr()) as usize) + let target_pc = (symbol.st_value.saturating_sub(text_section.sh_addr) as usize) .checked_div(ebpf::INSN_SIZE) .unwrap_or_default(); let name = elf - .symbol_name(symbol.st_name() as Elf64Word) - .ok_or_else(|| ElfError::UnknownSymbol(symbol.st_name() as usize))?; + .symbol_name(symbol.st_name as Elf64Word) + .map_err(|_| ElfError::UnknownSymbol(symbol.st_name as usize))?; function_registry.register_function_hashed_legacy( loader, !sbpf_version.static_syscalls(), @@ -1217,8 +1230,8 @@ mod test { #[test] fn test_validate() { let elf_bytes = std::fs::read("tests/elfs/relative_call.so").unwrap(); - let elf = NewParser::parse(&elf_bytes).unwrap(); - let mut header = elf.header().clone(); + let elf = Elf64::parse(&elf_bytes).unwrap(); + let mut header = elf.file_header().clone(); let config = Config::default(); @@ -1233,62 +1246,46 @@ mod test { header.e_ident.ei_class = ELFCLASS32; let bytes = write_header(header.clone()); // the new parser rejects anything other than ELFCLASS64 directly - NewParser::parse(&bytes).expect_err("allowed bad class"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) - .expect_err("allowed bad class"); + Elf64::parse(&bytes).expect_err("allowed bad class"); header.e_ident.ei_class = ELFCLASS64; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect("validation failed"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect("validation failed"); header.e_ident.ei_data = ELFDATA2MSB; let bytes = write_header(header.clone()); // the new parser only supports little endian - NewParser::parse(&bytes).expect_err("allowed big endian"); + Elf64::parse(&bytes).expect_err("allowed big endian"); header.e_ident.ei_data = ELFDATA2LSB; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect("validation failed"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect("validation failed"); header.e_ident.ei_osabi = 1; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect_err("allowed wrong abi"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect_err("allowed wrong abi"); header.e_ident.ei_osabi = ELFOSABI_NONE; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect("validation failed"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect("validation failed"); header.e_machine = 42; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect_err("allowed wrong machine"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect_err("allowed wrong machine"); header.e_machine = EM_BPF; let bytes = write_header(header.clone()); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect("validation failed"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect("validation failed"); header.e_type = ET_REL; let bytes = write_header(header); - ElfExecutable::validate(&config, &NewParser::parse(&bytes).unwrap(), &elf_bytes) - .expect_err("allowed wrong type"); - ElfExecutable::validate(&config, &GoblinParser::parse(&bytes).unwrap(), &elf_bytes) + ElfExecutable::validate(&config, &Elf64::parse(&bytes).unwrap(), &elf_bytes) .expect_err("allowed wrong type"); } @@ -1321,7 +1318,7 @@ mod test { file.read_to_end(&mut elf_bytes) .expect("failed to read elf file"); let elf = ElfExecutable::load(&elf_bytes, loader.clone()).expect("validation failed"); - let parsed_elf = NewParser::parse(&elf_bytes).unwrap(); + let parsed_elf = Elf64::parse(&elf_bytes).unwrap(); let executable: &Executable = &elf; assert_eq!(0, executable.get_entrypoint_instruction_offset()); @@ -1331,7 +1328,7 @@ mod test { bytes }; - let mut header = parsed_elf.header().clone(); + let mut header = parsed_elf.file_header().clone(); let initial_e_entry = header.e_entry; header.e_entry += 8; @@ -1388,7 +1385,7 @@ mod test { let mut elf_bytes = Vec::new(); file.read_to_end(&mut elf_bytes) .expect("failed to read elf file"); - let parsed_elf = NewParser::parse(&elf_bytes).unwrap(); + let parsed_elf = Elf64::parse(&elf_bytes).unwrap(); // focus on elf header, small typically 64 bytes println!("mangle elf header"); @@ -1396,7 +1393,7 @@ mod test { &elf_bytes, 1_000_000, 100, - 0..parsed_elf.header().e_ehsize as usize, + 0..parsed_elf.file_header().e_ehsize as usize, 0..255, |bytes: &mut [u8]| { let _ = ElfExecutable::load(bytes, loader.clone()); @@ -1409,7 +1406,7 @@ mod test { &elf_bytes, 1_000_000, 100, - parsed_elf.header().e_shoff as usize..elf_bytes.len(), + parsed_elf.file_header().e_shoff as usize..elf_bytes.len(), 0..255, |bytes: &mut [u8]| { let _ = ElfExecutable::load(bytes, loader.clone()); @@ -1970,8 +1967,8 @@ mod test { fn test_long_section_name() { let elf_bytes = std::fs::read("tests/elfs/long_section_name.so").unwrap(); assert_error!( - NewParser::parse(&elf_bytes), - "FailedToParse(\"Section or symbol name `{}` is longer than `{}` bytes\")", + Elf64::parse(&elf_bytes), + "StringTooLong({:?}, {})", ".bss.__rust_no_alloc_shim_is_unstable" .get(0..SECTION_NAME_LENGTH_MAXIMUM) .unwrap(), diff --git a/src/elf_parser/mod.rs b/src/elf_parser/mod.rs index 288c35cc..d81e8879 100644 --- a/src/elf_parser/mod.rs +++ b/src/elf_parser/mod.rs @@ -62,6 +62,53 @@ pub enum ElfParserError { NoDynamicStringTable, } +impl Elf64Phdr { + /// Returns the segment virtual address range. + pub fn vm_range(&self) -> Range { + let addr = self.p_vaddr; + addr..addr.saturating_add(self.p_memsz) + } +} + +impl Elf64Shdr { + /// Returns whether the section is writable. + pub fn is_writable(&self) -> bool { + self.sh_flags & (SHF_ALLOC | SHF_WRITE) == SHF_ALLOC | SHF_WRITE + } + + /// Returns the byte range the section spans in the file. + pub fn file_range(&self) -> Option> { + (self.sh_type != SHT_NOBITS).then(|| { + let offset = self.sh_offset as usize; + offset..offset.saturating_add(self.sh_size as usize) + }) + } + + /// Returns the virtual address range. + pub fn vm_range(&self) -> Range { + self.sh_addr..self.sh_addr.saturating_add(self.sh_size) + } +} + +impl Elf64Sym { + /// Returns whether the symbol is a function. + pub fn is_function(&self) -> bool { + (self.st_info & 0xF) == STT_FUNC + } +} + +impl Elf64Rel { + /// Returns the relocation type. + pub fn r_type(&self) -> Elf64Word { + (self.r_info & 0xFFFFFFFF) as Elf64Word + } + + /// Returns the symbol index. + pub fn r_sym(&self) -> Elf64Word { + self.r_info.checked_shr(32).unwrap_or(0) as Elf64Word + } +} + fn check_that_there_is_no_overlap( range_a: &Range, range_b: &Range, diff --git a/src/elf_parser_glue.rs b/src/elf_parser_glue.rs deleted file mode 100644 index e04fe736..00000000 --- a/src/elf_parser_glue.rs +++ /dev/null @@ -1,566 +0,0 @@ -//! Internal ELF parser abstraction. -use std::{borrow::Cow, convert::TryInto, iter, ops::Range, slice}; - -use goblin::{ - elf::{Elf, Header, ProgramHeader, Reloc, SectionHeader, Sym}, - elf64::{ - header::{EI_ABIVERSION, EI_CLASS, EI_DATA, EI_OSABI, EI_VERSION}, - reloc::RelocIterator, - sym::SymIterator, - }, - error::Error as GoblinError, -}; - -use crate::{ - elf::ElfError, - elf_parser::{ - consts::{SHF_ALLOC, SHF_WRITE, SHT_NOBITS, STT_FUNC}, - types::{ - Elf64Addr, Elf64Ehdr, Elf64Off, Elf64Phdr, Elf64Rel, Elf64Shdr, Elf64Sym, Elf64Word, - Elf64Xword, ElfIdent, - }, - Elf64, ElfParserError, - }, - error::EbpfError, -}; - -/// The common trait implemented by LegacyParser and NewParser. -/// -/// This is an internal interface used to isolate the ELF parsing bits and to be -/// able to plug the old goblin parser or the new parser depending on config. -/// -/// The interface is pretty straightforward. The associated types are the types -/// used to represent ELF data. Some return values are `Cow` since goblin -/// returns some data by value, while the new parser always borrows from the -/// underlying file slice. -pub trait ElfParser<'a>: Sized { - /// Program header type. - type ProgramHeader: ElfProgramHeader + 'a; - /// Iterator of program headers. - type ProgramHeaders: Iterator; - - /// Section header type. - type SectionHeader: ElfSectionHeader + 'a; - /// Iterator of section headers - type SectionHeaders: Iterator; - - /// Symbol type. - type Symbol: ElfSymbol + 'a; - /// Iterator of symbols. - type Symbols: Iterator>; - - /// Relocation type. - type Relocation: ElfRelocation + 'a; - /// Iterator of relocations. - type Relocations: Iterator>; - - /// Parses the ELF data included in the buffer. - fn parse(data: &'a [u8]) -> Result; - - /// Returns the file header. - fn header(&self) -> &Elf64Ehdr; - - /// Returns the program headers. - fn program_headers(&'a self) -> Self::ProgramHeaders; - - /// Returns the section headers. - fn section_headers(&'a self) -> Self::SectionHeaders; - - /// Returns the section with the given `name`. - fn section(&self, name: &[u8]) -> Result; - - /// Returns the section name at the given `sh_name` offset. - fn section_name(&self, sh_name: Elf64Word) -> Option<&[u8]>; - - /// Returns the symbols included in the symbol table. - fn symbols(&'a self) -> Self::Symbols; - - /// Returns the symbol name at the given `st_name` offset. - fn symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]>; - - /// Returns the symbols included in the dynamic symbol table. - fn dynamic_symbol(&self, index: Elf64Word) -> Option; - - /// Returns the dynamic symbol name at the given `st_name` offset. - fn dynamic_symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]>; - - /// Returns the dynamic relocations. - fn dynamic_relocations(&'a self) -> Self::Relocations; -} - -/// ELF program header. -pub trait ElfProgramHeader { - /// Returns the segment virtual address. - fn p_vaddr(&self) -> Elf64Addr; - - /// Returns the segment size when loaded in memory. - fn p_memsz(&self) -> Elf64Xword; - - /// Returns the segment file offset. - fn p_offset(&self) -> Elf64Off; - - /// Returns the segment virtual address range. - fn vm_range(&self) -> Range { - let addr = self.p_vaddr(); - addr..addr.saturating_add(self.p_memsz()) - } -} - -/// ELF section header. -pub trait ElfSectionHeader { - /// Returns the section name offset. - fn sh_name(&self) -> Elf64Word; - - /// Returns the section virtual address. - fn sh_addr(&self) -> Elf64Addr; - - /// Returns the section file offset. - fn sh_offset(&self) -> Elf64Off; - - /// Returns the section size. - fn sh_size(&self) -> Elf64Xword; - - /// Returns the section flags. - fn sh_flags(&self) -> Elf64Xword; - - /// Returns the section type. - fn sh_type(&self) -> Elf64Word; - - /// Returns whether the section is writable. - fn is_writable(&self) -> bool { - self.sh_flags() & (SHF_ALLOC | SHF_WRITE) == SHF_ALLOC | SHF_WRITE - } - - /// Returns the byte range the section spans in the file. - fn file_range(&self) -> Option> { - (self.sh_type() != SHT_NOBITS).then(|| { - let offset = self.sh_offset() as usize; - offset..offset.saturating_add(self.sh_size() as usize) - }) - } - - /// Returns the virtual address range. - fn vm_range(&self) -> Range { - let addr = self.sh_addr(); - addr..addr.saturating_add(self.sh_size()) - } -} - -/// ELF symbol. -pub trait ElfSymbol: Clone { - /// Returns the symbol name offset. - fn st_name(&self) -> Elf64Word; - - /// Returns the symbol type and binding attributes. - fn st_info(&self) -> u8; - - /// Returns the value associated with the symbol. - fn st_value(&self) -> Elf64Addr; - - /// Returns whether the symbol is a function. - fn is_function(&self) -> bool { - (self.st_info() & 0xF) == STT_FUNC - } -} - -/// ELF relocation. -pub trait ElfRelocation: Clone { - /// Returns the offset where to apply the relocation. - fn r_offset(&self) -> Elf64Addr; - - /// Returns the relocation type. - fn r_type(&self) -> Elf64Word; - - /// Returns the symbol index. - fn r_sym(&self) -> Elf64Word; -} - -/// The Goblin based ELF parser. -pub struct GoblinParser<'a> { - elf: Elf<'a>, - header: Elf64Ehdr, -} - -impl<'a> ElfParser<'a> for GoblinParser<'a> { - type ProgramHeader = ProgramHeader; - type ProgramHeaders = slice::Iter<'a, ProgramHeader>; - - type SectionHeader = SectionHeader; - type SectionHeaders = slice::Iter<'a, SectionHeader>; - - type Symbol = Sym; - type Symbols = iter::Map, fn(Self::Symbol) -> Cow<'a, Self::Symbol>>; - - type Relocation = Reloc; - type Relocations = - iter::Map, fn(Self::Relocation) -> Cow<'a, Self::Relocation>>; - - fn parse(data: &'a [u8]) -> Result, ElfError> { - let elf = Elf::parse(data)?; - Ok(Self { - header: elf.header.into(), - elf, - }) - } - - fn header(&self) -> &Elf64Ehdr { - &self.header - } - - fn program_headers(&'a self) -> Self::ProgramHeaders { - self.elf.program_headers.iter() - } - - fn section_headers(&'a self) -> Self::SectionHeaders { - self.elf.section_headers.iter() - } - - fn section(&self, name: &[u8]) -> Result { - match self.elf.section_headers.iter().find(|section_header| { - if let Some(this_name) = self.section_name(section_header.sh_name as Elf64Word) { - return this_name == name; - } - false - }) { - Some(section) => Ok(section.clone()), - None => Err(ElfError::SectionNotFound( - std::str::from_utf8(name) - .unwrap_or("UTF-8 error") - .to_string(), - )), - } - } - - fn section_name(&self, sh_name: Elf64Word) -> Option<&[u8]> { - self.elf - .shdr_strtab - .get_at(sh_name as usize) - .map(|name| name.as_bytes()) - } - - fn symbols(&'a self) -> Self::Symbols { - self.elf.syms.iter().map(Cow::Owned) - } - - fn symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]> { - self.elf - .strtab - .get_at(st_name as usize) - .map(|name| name.as_bytes()) - } - - fn dynamic_symbol(&self, index: Elf64Word) -> Option { - self.elf.dynsyms.get(index as usize) - } - - fn dynamic_symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]> { - self.elf - .dynstrtab - .get_at(st_name as usize) - .map(|name| name.as_bytes()) - } - - fn dynamic_relocations(&self) -> Self::Relocations { - self.elf.dynrels.iter().map(Cow::Owned) - } -} - -impl From

for Elf64Ehdr { - fn from(h: Header) -> Self { - Elf64Ehdr { - e_ident: ElfIdent { - ei_mag: h.e_ident[0..4].try_into().unwrap(), - ei_class: h.e_ident[EI_CLASS], - ei_data: h.e_ident[EI_DATA], - ei_version: h.e_ident[EI_VERSION], - ei_osabi: h.e_ident[EI_OSABI], - ei_abiversion: h.e_ident[EI_ABIVERSION], - ei_pad: [0u8; 7], - }, - e_type: h.e_type, - e_machine: h.e_machine, - e_version: h.e_version, - e_entry: h.e_entry, - e_phoff: h.e_phoff, - e_shoff: h.e_shoff, - e_flags: h.e_flags, - e_ehsize: h.e_ehsize, - e_phentsize: h.e_phentsize, - e_phnum: h.e_phnum, - e_shentsize: h.e_shentsize, - e_shnum: h.e_shnum, - e_shstrndx: h.e_shstrndx, - } - } -} - -impl ElfProgramHeader for ProgramHeader { - fn p_vaddr(&self) -> Elf64Addr { - self.p_vaddr - } - - fn p_memsz(&self) -> Elf64Xword { - self.p_memsz - } - - fn p_offset(&self) -> Elf64Off { - self.p_offset - } -} - -impl ElfSectionHeader for SectionHeader { - fn sh_name(&self) -> Elf64Word { - self.sh_name as _ - } - - fn sh_flags(&self) -> Elf64Xword { - self.sh_flags - } - - fn sh_addr(&self) -> Elf64Addr { - self.sh_addr - } - - fn sh_offset(&self) -> Elf64Off { - self.sh_offset - } - - fn sh_size(&self) -> Elf64Xword { - self.sh_size - } - - fn sh_type(&self) -> Elf64Word { - self.sh_type - } -} - -impl ElfSymbol for Sym { - fn st_name(&self) -> Elf64Word { - self.st_name as _ - } - - fn st_info(&self) -> u8 { - self.st_info - } - - fn st_value(&self) -> Elf64Addr { - self.st_value - } -} - -impl ElfRelocation for Reloc { - fn r_offset(&self) -> Elf64Addr { - self.r_offset - } - - fn r_type(&self) -> Elf64Word { - self.r_type - } - - fn r_sym(&self) -> Elf64Word { - self.r_sym as Elf64Word - } -} - -/// The new ELF parser. -#[derive(Debug)] -pub struct NewParser<'a> { - elf: Elf64<'a>, -} - -impl<'a> ElfParser<'a> for NewParser<'a> { - type ProgramHeader = Elf64Phdr; - type ProgramHeaders = slice::Iter<'a, Self::ProgramHeader>; - - type SectionHeader = Elf64Shdr; - type SectionHeaders = slice::Iter<'a, Self::SectionHeader>; - - type Symbol = Elf64Sym; - type Symbols = - iter::Map, fn(&'a Self::Symbol) -> Cow<'a, Self::Symbol>>; - - type Relocation = Elf64Rel; - type Relocations = iter::Map< - slice::Iter<'a, Self::Relocation>, - fn(&'a Self::Relocation) -> Cow<'a, Self::Relocation>, - >; - - fn parse(data: &'a [u8]) -> Result, ElfError> { - Ok(Self { - elf: Elf64::parse(data)?, - }) - } - - fn header(&self) -> &Elf64Ehdr { - self.elf.file_header() - } - - fn program_headers(&'a self) -> Self::ProgramHeaders { - self.elf.program_header_table().iter() - } - - fn section_headers(&'a self) -> Self::SectionHeaders { - self.elf.section_header_table().iter() - } - - fn section(&self, name: &[u8]) -> Result { - for section_header in self.elf.section_header_table() { - if self.elf.section_name(section_header.sh_name)? == name { - return Ok(section_header.clone()); - } - } - - Err(ElfError::SectionNotFound( - std::str::from_utf8(name) - .unwrap_or("UTF-8 error") - .to_string(), - )) - } - - fn section_name(&self, sh_name: Elf64Word) -> Option<&[u8]> { - self.elf.section_name(sh_name).ok() - } - - fn symbols(&'a self) -> Self::Symbols { - self.elf - .symbol_table() - .ok() - .flatten() - .unwrap_or(&[]) - .iter() - .map(Cow::Borrowed) - } - - fn symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]> { - self.elf.symbol_name(st_name).ok() - } - - fn dynamic_symbol(&self, index: Elf64Word) -> Option { - self.elf - .dynamic_symbol_table() - .and_then(|table| table.get(index as usize).cloned()) - } - - fn dynamic_symbol_name(&self, st_name: Elf64Word) -> Option<&[u8]> { - self.elf.dynamic_symbol_name(st_name).ok() - } - - fn dynamic_relocations(&'a self) -> Self::Relocations { - self.elf - .dynamic_relocations_table() - .unwrap_or(&[]) - .iter() - .map(Cow::Borrowed) - } -} - -impl ElfProgramHeader for Elf64Phdr { - fn p_vaddr(&self) -> Elf64Addr { - self.p_vaddr - } - - fn p_memsz(&self) -> Elf64Xword { - self.p_memsz - } - - fn p_offset(&self) -> Elf64Off { - self.p_offset - } -} - -impl ElfSectionHeader for Elf64Shdr { - fn sh_name(&self) -> Elf64Word { - self.sh_name as _ - } - - fn sh_flags(&self) -> Elf64Xword { - self.sh_flags - } - - fn sh_addr(&self) -> Elf64Addr { - self.sh_addr - } - - fn sh_offset(&self) -> Elf64Off { - self.sh_offset - } - - fn sh_size(&self) -> Elf64Xword { - self.sh_size - } - - fn sh_type(&self) -> Elf64Word { - self.sh_type - } -} - -impl ElfSymbol for Elf64Sym { - fn st_name(&self) -> Elf64Word { - self.st_name - } - - fn st_info(&self) -> u8 { - self.st_info - } - - fn st_value(&self) -> Elf64Addr { - self.st_value - } -} - -impl ElfRelocation for Elf64Rel { - fn r_offset(&self) -> Elf64Addr { - self.r_offset - } - - fn r_type(&self) -> Elf64Word { - (self.r_info & 0xFFFFFFFF) as Elf64Word - } - - fn r_sym(&self) -> Elf64Word { - self.r_info.checked_shr(32).unwrap_or(0) as Elf64Word - } -} - -impl From for ElfError { - fn from(err: ElfParserError) -> Self { - match err { - ElfParserError::InvalidSectionHeader - | ElfParserError::InvalidString - | ElfParserError::StringTooLong(_, _) - | ElfParserError::InvalidSize - | ElfParserError::Overlap - | ElfParserError::SectionNotInOrder - | ElfParserError::NoSectionNameStringTable - | ElfParserError::InvalidDynamicSectionTable - | ElfParserError::InvalidRelocationTable - | ElfParserError::InvalidAlignment - | ElfParserError::NoStringTable - | ElfParserError::NoDynamicStringTable - | ElfParserError::InvalidFileHeader => ElfError::FailedToParse(err.to_string()), - ElfParserError::InvalidProgramHeader => ElfError::InvalidProgramHeader, - ElfParserError::OutOfBounds => ElfError::ValueOutOfBounds, - } - } -} - -impl From for ElfError { - fn from(error: GoblinError) -> Self { - match error { - GoblinError::Malformed(string) => Self::FailedToParse(format!("malformed: {string}")), - GoblinError::BadMagic(magic) => Self::FailedToParse(format!("bad magic: {magic:#x}")), - GoblinError::Scroll(error) => Self::FailedToParse(format!("read-write: {error}")), - GoblinError::IO(error) => Self::FailedToParse(format!("io: {error}")), - GoblinError::BufferTooShort(n, error) => { - Self::FailedToParse(format!("buffer too short {n} {error}")) - } - _ => Self::FailedToParse("cause unkown".to_string()), - } - } -} - -impl From for EbpfError { - fn from(error: GoblinError) -> Self { - ElfError::from(error).into() - } -} diff --git a/src/lib.rs b/src/lib.rs index fdf9fc64..573d8810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ pub mod disassembler; pub mod ebpf; pub mod elf; pub mod elf_parser; -pub mod elf_parser_glue; pub mod error; pub mod fuzz; pub mod insn_builder; diff --git a/src/vm.rs b/src/vm.rs index 3393a387..720a1212 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -78,8 +78,6 @@ pub struct Config { pub reject_callx_r10: bool, /// Avoid copying read only sections when possible pub optimize_rodata: bool, - /// Use the new ELF parser - pub new_elf_parser: bool, /// Use aligned memory mapping pub aligned_memory_mapping: bool, /// Allow ExecutableCapability::V1 @@ -112,7 +110,6 @@ impl Default for Config { external_internal_function_hash_collision: true, reject_callx_r10: true, optimize_rodata: true, - new_elf_parser: true, aligned_memory_mapping: true, enable_sbpf_v1: true, enable_sbpf_v2: true, diff --git a/test_utils/Cargo.lock b/test_utils/Cargo.lock index 0e7e3674..057e7087 100644 --- a/test_utils/Cargo.lock +++ b/test_utils/Cargo.lock @@ -56,17 +56,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "goblin" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c955ab4e0ad8c843ea653a3d143048b87490d9be56bd7132a435c2407846ac8f" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "hash32" version = "0.2.1" @@ -97,12 +86,6 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "ppv-lite86" version = "0.2.9" @@ -168,20 +151,6 @@ name = "scroll" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "solana_rbpf" @@ -189,7 +158,6 @@ version = "0.8.1" dependencies = [ "byteorder", "combine", - "goblin", "hash32", "libc", "log", @@ -197,6 +165,7 @@ dependencies = [ "rustc-demangle", "scroll", "thiserror", + "winapi", ] [[package]] @@ -264,3 +233,25 @@ name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"