X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/afe874b1634377ecb27057ee76deb04915bb34d7..ebf6f43431fe84b7b17822014a6d1f0169516e93:/src/other/machochecker.cpp diff --git a/src/other/machochecker.cpp b/src/other/machochecker.cpp index 4841c7c..36a71fd 100644 --- a/src/other/machochecker.cpp +++ b/src/other/machochecker.cpp @@ -388,6 +388,7 @@ void MachOChecker::checkLoadCommands() // check that all load commands fit within the load command space file const macho_encryption_info_command

* encryption_info = NULL; const macho_thread_command

* threadInfo = NULL; + const macho_entry_point_command

* entryPoint = NULL; const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength; const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header

) + fHeader->sizeofcmds(); const uint32_t cmd_count = fHeader->ncmds(); @@ -424,8 +425,12 @@ void MachOChecker::checkLoadCommands() case LC_LOAD_UPWARD_DYLIB: case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: - case LC_FUNCTION_STARTS: case LC_RPATH: + case LC_FUNCTION_STARTS: + case LC_DYLD_ENVIRONMENT: + case LC_DATA_IN_CODE: + case LC_DYLIB_CODE_SIGN_DRS: + case LC_SOURCE_VERSION: break; case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: @@ -439,6 +444,11 @@ void MachOChecker::checkLoadCommands() if ( fHeader->flags() & MH_NO_REEXPORTED_DYLIBS ) throw "MH_NO_REEXPORTED_DYLIBS bit of mach_header flags should not be set in an image with LC_SUB_LIBRARY or LC_SUB_UMBRELLA"; break; + case LC_MAIN: + if ( fHeader->filetype() != MH_EXECUTE ) + throw "LC_MAIN can only be used in MH_EXECUTE file types"; + entryPoint = (macho_entry_point_command

*)cmd; + break; case LC_UNIXTHREAD: if ( fHeader->filetype() != MH_EXECUTE ) throw "LC_UNIXTHREAD can only be used in MH_EXECUTE file types"; @@ -590,7 +600,11 @@ void MachOChecker::checkLoadCommands() if ( (initialPC < fTEXTSegment->vmaddr()) || (initialPC >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialPC); } - + else if ( entryPoint != NULL ) { + pint_t initialOffset = entryPoint->entryoff(); + if ( (initialOffset < fTEXTSegment->fileoff()) || (initialOffset >= (fTEXTSegment->fileoff()+fTEXTSegment->filesize())) ) + throwf("entry point 0x%0llX is outside __TEXT segment", (long long)initialOffset); + } // checks for executables bool isStaticExecutable = false; @@ -607,7 +621,7 @@ void MachOChecker::checkLoadCommands() cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); } if ( isStaticExecutable ) { - if ( fHeader->flags() != MH_NOUNDEFS ) + if ( (fHeader->flags() != MH_NOUNDEFS) && (fHeader->flags() != (MH_NOUNDEFS|MH_PIE)) ) throw "invalid bits in mach_header flags for static executable"; } } @@ -661,7 +675,7 @@ void MachOChecker::checkLoadCommands() break; case LC_DYSYMTAB: { - if ( isStaticExecutable ) + if ( isStaticExecutable &&! fSlidableImage ) throw "LC_DYSYMTAB should not be used in static executable"; foundDynamicSymTab = true; fDynamicSymbolTable = (macho_dysymtab_command

*)cmd; @@ -725,6 +739,32 @@ void MachOChecker::checkLoadCommands() throw "function starts data size not a multiple of pointer size"; } break; + case LC_DATA_IN_CODE: + { + const macho_linkedit_data_command

* info = (macho_linkedit_data_command

*)cmd; + if ( info->dataoff() < linkEditSegment->fileoff() ) + throw "data-in-code data not in __LINKEDIT"; + if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "data-in-code data not in __LINKEDIT"; + if ( (info->dataoff() % sizeof(pint_t)) != 0 ) + throw "data-in-code data table not pointer aligned"; + if ( (info->datasize() % sizeof(pint_t)) != 0 ) + throw "data-in-code data size not a multiple of pointer size"; + } + break; + case LC_DYLIB_CODE_SIGN_DRS: + { + const macho_linkedit_data_command

* info = (macho_linkedit_data_command

*)cmd; + if ( info->dataoff() < linkEditSegment->fileoff() ) + throw "dependent dylib DR data not in __LINKEDIT"; + if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) ) + throw "dependent dylib DR data not in __LINKEDIT"; + if ( (info->dataoff() % sizeof(pint_t)) != 0 ) + throw "dependent dylib DR data table not pointer aligned"; + if ( (info->datasize() % sizeof(pint_t)) != 0 ) + throw "dependent dylib DR data size not a multiple of pointer size"; + } + break; } cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); } @@ -1039,6 +1079,7 @@ void MachOChecker::checkExternalReloation(const macho_relocation_info

// FIX: check r_symbol } +#if SUPPORT_ARCH_arm_any template <> void MachOChecker::checkExternalReloation(const macho_relocation_info

* reloc) { @@ -1054,6 +1095,7 @@ void MachOChecker::checkExternalReloation(const macho_relocation_info

* r throw "external relocation address not in writable segment"; // FIX: check r_symbol } +#endif template <> @@ -1066,9 +1108,6 @@ void MachOChecker::checkLocalReloation(const macho_relocation_info

* relo } else { - // ignore pair relocs - if ( reloc->r_type() == PPC_RELOC_PAIR ) - return; // FIX if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) ) throwf("local relocation address 0x%08X not in writable segment", reloc->r_address()); @@ -1112,6 +1151,7 @@ void MachOChecker::checkLocalReloation(const macho_relocation_info

* r throw "local relocation address not in writable segment"; } +#if SUPPORT_ARCH_arm_any template <> void MachOChecker::checkLocalReloation(const macho_relocation_info

* reloc) { @@ -1132,6 +1172,7 @@ void MachOChecker::checkLocalReloation(const macho_relocation_info

* relo throw "local relocation address not in writable segment"; } } +#endif template void MachOChecker::checkRelocations() @@ -1276,6 +1317,7 @@ bool MachOChecker::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd) } } } + return false; } template @@ -1521,12 +1563,14 @@ static void check(const char* path) else throw "in universal file, x86_64 slice does not contain x86_64 mach-o"; break; +#if SUPPORT_ARCH_arm_any case CPU_TYPE_ARM: if ( MachOChecker::validFile(p + offset) ) MachOChecker::make(p + offset, size, path); else throw "in universal file, arm slice does not contain arm mach-o"; break; +#endif default: throwf("in universal file, unknown architecture slice 0x%x\n", cputype); } @@ -1544,9 +1588,11 @@ static void check(const char* path) else if ( MachOChecker::validFile(p) ) { MachOChecker::make(p, length, path); } +#if SUPPORT_ARCH_arm_any else if ( MachOChecker::validFile(p) ) { MachOChecker::make(p, length, path); } +#endif else { throw "not a known file type"; }