Rebase the PowerPC64 ELFv1 initial TOC value - #814
Conversation
ppc64_initial_rtoc returns a mapped address under ELFv2, where it comes from the .got section's vaddr, and a link-time address under ELFv1, where it is read straight out of the entry descriptor. The entry point word beside it in that same descriptor goes through AT.from_lva(...).to_mva() in Backend.entry, so an ELFv1 shared object reports a rebased entry point and an unrebased TOC. tests/ppc64/libc.so.6 mapped at 0x10100000 reports 0x1cc6f0; its mapped .got plus 0x8000, and the descriptor word after cle resolves the R_PPC64_RELATIVE over it, are both 0x102cc6f0. angr's SimLinux puts the attribute straight into r2, so a plain Project on that object starts with r2 one base too low. _ppc64_abiv1_entry_fix runs from ELF.__init__, before the loader picks a base, so the translation belongs in the property rather than in the read.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Loader and entry-state values for Before — the TOC is reported at its link-time address, cle master 3812052After — the property agrees with the relocated descriptor word and with the mapped with this change |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
Caveats: the three full-suite failures are |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_814 |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
MetaELF.ppc64_initial_rtocreturns a link-time address for PowerPC64 ELFv1 objects, soan object the loader moves reports a TOC pointer that is not where its TOC is.
tests/ppc64/libc.so.6from angr/binaries loads at0x400000underangr.Project(path, auto_load_libs=False)and reports this:The entry point comes out of the same function descriptor as the TOC and is rebased; the
TOC is not. angr's
set_entry_register_valuesstores the attribute straight intor2, soa plain
Projecton that file starts withr2one base too low, and every TOC-relativeload from it addresses memory outside the image. Any ELFv1 object the loader moves is
wrong by the distance it moved. ELFv2 is unaffected.
Root cause
_ppc64_abiv1_entry_fixunpacks both words out of the ELFv1 entry descriptor and storesthem as they appear in the file:
Backend.entrytranslates the first on the way out, withreturn AT.from_lva(self._entry, self).to_mva().ppc64_initial_rtocreturned the secondunchanged. The ELFv2 branch beside it computes from
sections_map[".got"].vaddr, whichRegion._rebasehas already moved, so one property returned a mapped address under oneABI and a linked address under the other. The two branches have meant different things
since the ELFv2 one arrived in #218.
Fix
Translate the ELFv1 value in the property, the way
Backend.entrytranslates the entrypoint, and leave
Nonealone for a relocatable object that has no descriptor to read. Itbelongs in the property rather than in
_ppc64_abiv1_entry_fix, because that runs fromELF.__init__before the loader has picked a base.ppc64_initial_rtocis now a mappedaddress for every object:
0x5cc6f0is also that object's mapped.gotplus0x8000, and the word cle itselfleaves at the descriptor once it has resolved the
R_PPC64_RELATIVEcovering it.Testing
tests/test_ppc64_initial_rtoc.py::test_ppc64_abiv1_rebasedloadstests/ppc64/libc.so.6at
0x10100000and asserts the TOC comes back as0x102cc6f0, cross-checked against themapped
.got; on master it comes back as0x1cc6f0and the test fails. The four existingtests in that file are untouched and pass on both revisions. Loading all seventeen
tracked files under
tests/ppc64/on both revisions, each alone and again with itslibraries, moves nothing but this attribute — across 61 object loads per revision the
memory backers and the symbol tables hash identically, and the 31 rows that differ are
libc.so.6andld64.so.1at the four bases they get mapped to.Validation: #814 (comment)
session: sharpen