442 Commits

Author SHA1 Message Date
Christopher Cole 6d6d1e23ce Rename elf::File -> elf::ElfStream and make it specific to the Read + Seek interface 2022-11-04 23:04:25 -07:00
Christopher Cole 90a9975712 Move some fuzz targets over to testing ElfBytes 2022-11-04 22:24:32 -07:00
Christopher Cole 4a4ad6e4c9 Expose the FileHeader on ElfBytes 2022-11-04 21:23:31 -07:00
Christopher Cole 54bee2ad5f Export ElfBytes and CommonElfSections at the top elf:: module level
This acts as one of the main parsing interfaces provided by this library, so I think
it fits nicely at top scope like this.
2022-11-04 20:48:18 -07:00
Christopher Cole 726f2b793e Remove elf_bytes::from_bytes() helper, since all it did was wrap ElfBytes::minimal_parse 2022-11-04 19:37:14 -07:00
Christopher Cole 6b0baf41cb Fix ElfBytes helper trait ReadBytesExt's SliceReadError to populate the correct start,end 2022-11-04 19:27:06 -07:00
Christopher Cole 15d4fe80bc Add more doc comments to ElfBytes 2022-11-04 19:21:13 -07:00
Christopher Cole f0a92a2c4b Rename ElfBytes::parse() -> ElfBytes::minimal_parse()
This better-communicates that only a minimal amount of parsing occurs in this method,
rather than the entire elf contents being parsed.
2022-11-04 18:54:14 -07:00
Christopher Cole 0873690791 Update the capabilities statements in the README.md 2022-11-04 18:13:00 -07:00
Christopher Cole 133fa08114 Rename gabi -> abi since it technically includes extension constants, too 2022-11-04 16:43:13 -07:00
Christopher Cole bf4354e33c Add toplevel doc comment descriptions to each of the modules 2022-11-04 16:36:54 -07:00
Christopher Cole dccd366a15 Lift elf_stream's conditional std feature check into lib.rs
This whole module is std-only, so there's non need to sprinkle those cfgs all over the file
2022-11-04 16:07:00 -07:00
Christopher Cole 293f0a2d60 Implement ElfBytes::find_common_sections()
This is an efficient way to locate the common ELF sections with one iteration
over the section headers. It does one parsing iteration over the section headers
then constructs lazy-parsing types around the various section data subslices
for the common elf sections that it finds.
2022-11-04 15:58:05 -07:00
Christopher Cole 04fdadd9b5 Pull find_shdrs and find_phdrs up to top level module scope 2022-11-04 15:09:57 -07:00
Christopher Cole 3c8ec10195 Move ElfStream into its own module 2022-11-04 15:01:21 -07:00
Christopher Cole 0f41f2b015 Move ElfBytes into its on module 2022-11-04 14:58:53 -07:00
Christopher Cole 35d241f6f3 Change ElfBytes to validate and construct the SegmentTable at parse-time
Other interface methods on ElfBytes want to use the phdrs, and there's
no need to discover and validate the table each time its needed.

This now performs that discovery and validation once with initial FileHeader
parsing, then simply clones the lazy ParsingTable on request, which is cheap -
its just copying a slice, not copying actual data bytes.
2022-11-04 14:51:20 -07:00
Christopher Cole b6681305e5 Change ElfBytes to validate and construct the SectionHeaderTable at parse-time
Most of the other interface methods on ElfBytes want to use the shdrs, and there's
no need to discover and validate the table each time its needed.

This now performs that discovery and validation once with initial FileHeader
parsing, then simply clones the lazy ParsingTable on request, which is cheap -
its just copying a slice, not copying actual data bytes.
2022-11-04 14:34:53 -07:00
Christopher Cole 6c261b885e Split ElfBytes and ElfStream into their own interfaces by removing the ElfParser Trait
The more I work with these, the more they feel like they should just be two distinct types
with their own interfaces, where the ElfParser trait really only serves to complicate the
implementations and get in the way.
2022-11-04 14:04:33 -07:00
Christopher Cole 879d6b5366 Specify explicit lifetimes on the ReadBytesExt helper trait
This more accurately states the lifetime guarantees for how this is used.
2022-11-04 13:55:20 -07:00
Christopher Cole 62b35934e3 Extend ElfParser trait with section_data_as_symbol_table, symbol_table, and dynamic_symbol_table 2022-11-04 00:16:34 -07:00
Christopher Cole 798e28d156 Extend ElfParser trait with dynamic()
Gets a lazy-parsing iterator over the Dyn entries in the .dynamic section or PT_DYNAMIC segment
2022-11-03 23:42:46 -07:00
Christopher Cole e58c7e9530 Extend ElfParser trait with section_headers_with_strtab()
The ElfBytes impl is so much simpler than the stream one due to
its ability to get work through multiple shared references!

The more I work with these two, the more they seem like they should
really just be two distinct types rather than trying to each impl the same
Trait. Maybe long term the ElfStream interface will diverge to provide
an interface that's easier to code and work with, with some lazy parsing
but also some allocate and parse-it-all to simplify the implementation, since
simpler (usually) means less bugs!
2022-11-03 23:24:31 -07:00
Christopher Cole 682bd99348 Extend ElfParser trait with segment_data() and segment_data_as_notes() 2022-11-03 22:44:06 -07:00
Christopher Cole acd1e5c797 Extend ElfParser trait with a few section_data_as_... methods
section_data_as_notes(): yields a NoteIterator for a given SHT_NOTE section
section_data_as_rels(): yields a RelIterator for a given SHT_REL section
section_data_as_relas(): yields a RelaIterator for a given SHT_RELA section
section_data_as_strtab(): yields a StringTable for a given SHT_STRTAB section
2022-11-03 22:30:21 -07:00
Christopher Cole 4327ba9929 Extend ElfParser trait with section_data() method
This gets the section data from the file and an Optional CompressionHeader
if the section's data is flagged as being compressed.

Returns an empty slice for SHT_NOBITS
2022-11-03 17:28:41 -07:00
Christopher Cole 3bcd325e0a Rework the new interfaces used by ElfBytes and ElfStream to get bytes
These don't need to be generic or exposed outside this file, now that these are
two distinct types. It's also more convenient to have get_bytes() return a Result
rather than an option that has to be interpreted everywhere.
2022-11-03 17:00:08 -07:00
Christopher Cole 15e476f449 Extend ElfParser trait with section_headers() method
This gets the SectionHeaderTable (if any) by itself (without any associated StringTable),
and properly handles e_shnum > SHN_LORESERVE.
2022-11-03 16:43:04 -07:00
Christopher Cole cb3e087131 Add a doc comment example for from_bytes() 2022-11-03 15:40:05 -07:00
Christopher Cole 70e05c111b First step of implementing a new ElfParser trait with an ElfBytes and ElfStream impl
There is an unfortunate complication with the current File impl, where bytes-based parsing methods
require a `&mut File` due to the Stream-based impl mutating its internal buffer cache. This is overly
restrictive and prevents users of the Bytes-based impl from doing otherwise safe things like
concurrently getting multiple lazy-parsing types for different pieces of the ElfBytes and parsing
from them in tandem.

The goal of this split is to allow ElfBytes to do just that - yield multiple different lazy-parsing
handles at the same time, while also allowing a more restrictive mutating ElfStream. Note that the
ElfParser trait is implemented on a shared reference for ElfBytes but an exclusive mutable reference
for ElfStream.

These will eventually usurp and replace the existing File interface.
2022-11-03 14:59:06 -07:00
Christopher Cole 9e9bbb84fb Expand on the doc comments in src/endian.rs 2022-11-03 13:19:29 -07:00
Christopher Cole 7c72fb0f3f Make ELF structures generic across the new endian-aware integer parsing trait EndianParse
This has four impls:
AnyEndian: Can be used to parse integers from byte-order from at runtime
LittleEndian: Can be used to always parse integers from little-endian order
BigEndian: Can be used to always parse integers from big-endian order
NativeEndian: Can be used to always parse integers in the configured target's native endian order

When using the more restricted impls (like LittleEndian), a ParseError::UnsupportedElfEndianness will
be returned if the user attempts to parse a BigEndian ELF file. When using the more restricted impls,
the integer parsing code gets optimized to skip the conditional dispatch for the appropriate endianness
conversion method, which can be useful for uses where you know your binary only wants to target
a fixed endianness.

Currently, the File::open_stream() method always uses AnyEndian, meaning it can parse either Big or Little
endian files. Future patches will expose the new impls.
2022-11-03 11:47:20 -07:00
Christopher Cole f876a89b44 Change SymbolVersionTable::new() to take Options instead of Default-empty iterators
This more accurately and explicitly states reality, and also makes some generic typing easier
for us later.
2022-11-03 00:26:23 -07:00
Christopher Cole a5aaa3330e Move validate_entsize onto ParseAt off from ParsingTable
This helps us out for future work where we make ParsingTable a more complicated type
2022-11-02 23:13:09 -07:00
Christopher Cole 1783b99aa1 Add a new impl of an endian-aware integer parsing trait
This has three impls:
AnyEndian: Can be used to choose how which byte-order to parse integers from at runtime
LittleEndian: Can be used to always parse integers from little-endian order
BigEndian: Can be used to always parse integers from big-endian order

The long term goal of this trait and these three impls is to use them in the ParseAt trait
in order to allow users of the library to decide whether or not they want the overhead of
AnyEndian (the run-time match statement to pick which endianness to parse as.
2022-11-02 22:16:33 -07:00
Christopher Cole 5de81cae98 Add gabi constants for SHN_ABS and SHN_COMMON 2022-11-02 16:56:37 -07:00
Christopher Cole 6b0974f6fa Define PT_GNU_PROPERTY constant in gabi.rs 2022-11-02 15:24:05 -07:00
Christopher Cole a30814d861 Dedupe some safe phdr.p_offset + phdr.p_filesz calculations with ProgramHeader::get_file_data_range()
I kept this as pub(crate) for now, as I'm not sure if the naming is confusing for users or not,
so I want to keep it out of the public interface for now.
2022-11-02 14:58:16 -07:00
Christopher Cole f46a28c22d Refactor internal impl of File::segments() to use FileHeader.get_phdrs_data_range()
This bundles together all the checked integer math to calculate the range with the
desire to keep File impl code as small as possible. My hope with this is to be
able to reasonably split the ELF Bytes and Stream interfaces into two distinct types
each with their small bits of code in order to allow the Bytes interface to work
via shared references rather than mut references.
2022-11-02 14:45:54 -07:00
Christopher Cole aa41e552ed Bump crate version to v0.6.0
New Features:
* Add fuzz targets for parts of our ELF parsing interface via cargo-fuzz
* Add SysVHashTable which interprets the contents of a SHT_HASH section
* Add StringTable::get_raw() to get an uninterpreted &[u8]
* Add ParsingTable.len() method to get the number of elements in the table
* Add some note n_type constants for GNU extension notes.
* Add default "to_str" feature to get &str for gabi constant names

Changed Interfaces:
* Change File::segments() to return a ParsingTable instead of just a ParsingIterator
* Change File's SectionHeader interfaces to provide a ParsingTable instead of just a ParsingIterator
* Remove deprecated File::section_data_for_header() in favor of File::section_data()
* Remove FileHeader wrapper types OSABI, Architecture, and ObjectFileType
* Remove ProgramHeader wrapper types ProgType and ProgFlag
* Remove Symbol wrapper types SymbolType SymbolBind SymbolVis
* Remove wrapper type SectionType
* Remove unhelpful SectionFlag wrapper type
* Remove Display impl for FileHeader, SectionHeader, ProgramHeader, Symbol
* Remove ParseError::UnsupportedElfVersion in favor of more general ParseError::UnsupportedVersion

Bug Fixes:
* Fix divide by zero panic when parsing a note with alignment of 0 (Error instead of panic)
* Use checked integer math all over the parsing code (Error instead of panic or overflow)
* Fix note parsing for 8-byte aligned .note.gnu.property sections (Successfully parse instead of Erroring)
* Add size validation when parsing tables with entsizes (Error instead of panic)
2022-11-01 16:54:08 -07:00
Christopher Cole 125681c359 Optimize github fuzz action
The action environment apparently already has gcc & g++ installed, so there's no need to waste time with the apt-get update
2022-11-01 13:05:39 -07:00
Christopher Cole 801c887a9e Attempt at fixing fuzz github action tools install 2022-11-01 12:54:46 -07:00
Christopher Cole 5849b78f92 First attempt at a github fuzzing action
Not sure if this will work or not, and also not sure if there's a way to test a github action config without committing it... so... we'll do it live!
2022-11-01 12:45:29 -07:00
Christopher Cole 848f648996 Add some fuzz targets for some parts of our ELF parsing interface via cargo-fuzz
I decided to make multiple smaller fuzz targets like this in order to give each one
a smaller fuzzing domain to explore for that particular feature.
2022-11-01 12:14:15 -07:00
Christopher Cole 762f200231 Fix divide by zero panic when parsing a note with alignment of 0
This was caused by the alignment modulus calculation when fuzzing gave a note section header with zero-byte alignment
"attempt to calculate the remainder with a divisor of zero"
2022-11-01 11:48:39 -07:00
Christopher Cole 199caed7c2 Use checked integer math in GNU Symbol Versioning iterators 2022-11-01 11:08:54 -07:00
Christopher Cole 00986c6a05 Use checked integar math where appropriate in note.rs 2022-11-01 02:10:02 -07:00
Christopher Cole 07a567d3dd Use checked integer math in hash.rs 2022-11-01 02:00:35 -07:00
Christopher Cole d9d7cd4b79 Use checked integer math in File::symbol_version_table() 2022-11-01 01:13:00 -07:00
Christopher Cole 8e27fc920e Dedupe a lot of start, size, end calculations with SectionHeader::get_data_range()
I kept this as pub(crate) for now, as I'm not sure if the naming is confusing for users or not,
so I want to keep it out of the public interface for now.
2022-11-01 01:06:06 -07:00