elf: fix MIPS64 little-endian relocation parsing#519
Open
messense wants to merge 1 commit intom4b:masterfrom
Open
elf: fix MIPS64 little-endian relocation parsing#519messense wants to merge 1 commit intom4b:masterfrom
messense wants to merge 1 commit intom4b:masterfrom
Conversation
0d7b9ab to
27b25a2
Compare
Fix m4b#274: MIPS64 ELF uses a non-standard relocation info layout where the r_info field contains r_sym (32 bits) | r_ssym (8 bits) | r_type3 (8 bits) | r_type2 (8 bits) | r_type (8 bits), instead of the standard ELF64 format of (sym << 32) | type. On little-endian MIPS64 systems, when this struct is read as a single u64, the byte order causes the fields to be scrambled. This resulted in r_sym returning garbage values (e.g., 51511296 instead of 0), which then caused the dynamic symbol table parsing to try to read millions of symbols, failing with an out-of-bounds error. The fix applies a byte transformation (matching the approach used by LLVM and the `object` crate) to rearrange the MIPS64 LE r_info bytes into the standard ELF64 format before extracting r_sym and r_type. Changes: - Add `reloc64::mips64el_r_info()` to convert MIPS64 LE r_info to standard ELF64 format - Add `Reloc::fixup_mips64el()` to apply the transformation after parsing - Add `is_mips64el` flag to `RelocSection` and `RelocIterator` to conditionally apply the fixup during iteration/access - Add `RelocSection::parse_inner()` that accepts the `is_mips64el` flag - Detect MIPS64 LE in `Elf::parse_with_opts()` from the ELF header's e_machine and endianness - Backward compatible: `RelocSection::parse()` still works unchanged (defaults to no MIPS64 fixup) - Add comprehensive unit and integration tests
27b25a2 to
9dfc91e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #274 — MIPS64 LE ELF binaries fail to parse with an out-of-bounds error because
r_symandr_typereturn garbage values from the non-standard MIPS64 relocation layout.Background
MIPS64 ELF uses a non-standard relocation info (
r_info) layout different from standard ELF64:r_sym(32 bits) |r_type(32 bits)r_sym(32 bits) |r_ssym(8 bits) |r_type3(8 bits) |r_type2(8 bits) |r_type(8 bits)On little-endian MIPS64, when this struct is read as a single
u64, the byte order causes the fields to be scrambled. For example, anr_infowithr_sym=0andr_type=R_MIPS_REL32gets read as0x0312000000000000, causing:r_symto return 51,511,296 (instead of 0)r_typeto return 0 (instead of 3)The bogus
r_symthen causes the dynamic symbol table parsing to try to read millions of symbols, failing with an out-of-bounds error.Approach
Based on the maintainer's feedback from #382 — pass down whether it's a MIPS binary at runtime rather than using
#[cfg]compile-time conditionals:reloc64::mips64el_r_info()— Converts MIPS64 LEr_infoto standard ELF64 format using the same byte transformation as LLVM and theobjectcrateReloc::fixup_mips64el()— Applies the transformation after parsing a relocation entryRelocSection/RelocIterator— Carry anis_mips64elflag and conditionally apply the fixup duringget()and iterationElf::parse_with_opts()— Detects MIPS64 LE from the ELF header (e_machine == EM_MIPS && 64-bit && little-endian) and passes it through viaRelocSection::parse_inner()Backward Compatibility
RelocSection::parse()signature is unchanged (defaultsis_mips64el = false)RelocCtxtype alias is unchangedr_sym()/r_type()/r_info()functions are unchangedTests
Added 5 new tests:
test_mips64el_r_info— validates the byte transformation with real data from MIPS64 parse error: "type is too big (1236271128) for 137416" #274test_mips64el_r_info_with_sym— validates transformation when r_sym is non-zerotest_mips64el_r_info_zero— edge case: all-zero r_infotest_standard_r_sym_r_type_unchanged— ensures no regression for non-MIPStest_mips64el_reloc_section_parse— integration test through the fullRelocSectionpipeline, verifying both broken (without fix) and correct (with fix) behaviorReferences
#[cfg])objectcrate implementation