Load Mach-O bundles and kernel extensions - #728
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head Rebased from
Reproducer on the baseline, with a fixture that has been in import cle
cle.Loader("binaries/tests/aarch64/IPwnKit.macho.kext", auto_load_libs=False)
# cle.errors.CLECompatibilityError: Unsupported Mach-O file type: 11.
# Please open an issue if you need support for thisBaseline failures, one per defect:
Each production hunk was reverted on its own, with the rest of the change in place:
Scale, from a corpus sweep of 60,387 Mach-O and universal2 units loaded through Caveats:
|
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_728 |
The mach-o backend chose a base address with a chain of filetype tests whose else arm refused everything it had no rule for, so MH_BUNDLE, MH_KEXT_BUNDLE, MH_OBJECT and MH_DSYM were all rejected as unsupported even though nothing after that block reads the filetype at all. Bundles and kexts want the base address dylibs already get, because their segment vaddrs are relative to 0 as well, so give the three of them one branch. MH_OBJECT stays refused, since it needs the per-section mapping and relocation processing ELF does for ET_REL, and MH_DSYM stays refused too but now says it carries debug information rather than inviting a support request that should not be granted. The refusal named the filetype by number because IntEnum.__str__ has been int.__str__ since Python 3.11, and a filetype outside the enum escaped as a bare ValueError raised while formatting that same message. Parse the field into the enum once, where an unknown value becomes a CLECompatibilityError like every other malformed header this backend reports. A bundle binds its undefined symbols against the executable that dlopen-ed it, which both the symbol table and the chained fixup imports encode as library ordinal 255. That ordinal does not index imported_libraries, so resolving such a symbol raised IndexError out of Loader.__init__. Handle it beside the dynamic-lookup ordinal, which has the same shape. pic was computed with a bitwise and against MH_DYLIB on a field that holds an ordinal rather than a bitmask, so it was true for every filetype but MH_OBJECT, MH_BUNDLE and MH_DYLIB_STUB, including non-PIE executables that the loader then treated as rebasable. Test membership of the same zero-based filetypes instead, and let the executable branch stand on the filetype alone, which is what kept the wrong pic harmless there. tests/aarch64/IPwnKit.macho.kext has sat in the binaries repository unused since commit 2705d97 because it could not be loaded; it covers MH_KEXT_BUNDLE now. The other cases rewrite one header field of an existing fixture in a temporary copy.
8c8a77a to
eebcd25
Compare
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
The mach-o backend picks its base address with a chain of filetype tests whose else arm refuses everything it has no rule for, so kernel extensions, bundles, object files and dSYMs are all rejected as unsupported.
Bundles and kexts are linked relative to 0 exactly as dylibs are, so they share the dylib branch now. MH_OBJECT stays refused, since it needs the per-section mapping ELF does for ET_REL, and dSYMs stay refused but say they carry only debug information. The same block also let an unknown filetype escape as a bare ValueError and derived
picby masking a field that holds an ordinal. Separately, the library ordinal a bundle uses for symbols bound to whatever loaded it is not an index intoimported_libraries, and raised IndexError while resolving relocations.Regressions load
tests/aarch64/IPwnKit.macho.kext, unused in angr/binaries so far because it could not be loaded, and rewrite one header field of existing fixtures in temporary copies for the rest.Validation: #728 (comment)