Index: llvm/include/llvm/BinaryFormat/MachO.h =================================================================== --- llvm/include/llvm/BinaryFormat/MachO.h +++ llvm/include/llvm/BinaryFormat/MachO.h @@ -1014,6 +1014,14 @@ uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed }; +/// dyld_chained_starts_in_image is embedded in LC_DYLD_CHAINED_FIXUPS payload. +/// Each each seg_info_offset entry is the offset into this struct for that +/// segment followed by pool of dyld_chain_starts_in_segment data. +struct dyld_chained_starts_in_image { + uint32_t seg_count; + uint32_t seg_info_offset[1]; +}; + // Byte order swapping functions for MachO structs inline void swapStruct(fat_header &mh) { Index: llvm/include/llvm/Object/MachO.h =================================================================== --- llvm/include/llvm/Object/MachO.h +++ llvm/include/llvm/Object/MachO.h @@ -685,6 +685,9 @@ ArrayRef getDyldInfoBindOpcodes() const; ArrayRef getDyldInfoWeakBindOpcodes() const; ArrayRef getDyldInfoLazyBindOpcodes() const; + /// If the optional is None, no header was found, but the object was well-formed. + Expected> + getChainedFixupsHeader() const; Expected> getDyldChainedFixupTargets() const; ArrayRef getDyldInfoExportsTrie() const; ArrayRef getUuid() const; Index: llvm/lib/Object/MachOObjectFile.cpp =================================================================== --- llvm/lib/Object/MachOObjectFile.cpp +++ llvm/lib/Object/MachOObjectFile.cpp @@ -3259,13 +3259,13 @@ FixupKind Kind, bool Parse) : MachOAbstractFixupEntry(E, O), Kind(Kind) { ErrorAsOutParameter e(E); - if (Parse) { - if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) - FixupTargets = *FixupTargetsOrErr; - else { - *E = FixupTargetsOrErr.takeError(); - return; - } + if (!Parse) + return; + if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) + FixupTargets = *FixupTargetsOrErr; + else { + *E = FixupTargetsOrErr.takeError(); + return; } } @@ -3280,6 +3280,8 @@ } void MachOChainedFixupEntry::moveNext() { + ErrorAsOutParameter ErrAsOutParam(E); + Done = true; } @@ -4767,11 +4769,11 @@ return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } -Expected> -MachOObjectFile::getDyldChainedFixupTargets() const { +Expected> +MachOObjectFile::getChainedFixupsHeader() const { // Load the dyld chained fixups load command. if (!DyldChainedFixupsLoadCmd) - return std::vector(); + return None; auto DyldChainedFixupsOrErr = getStructOrErr(*this, DyldChainedFixupsLoadCmd); @@ -4780,11 +4782,10 @@ MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get(); // If the load command is present but the data offset has been zeroed out, - // as is the case for dylib stubs, return an empty list of targets. + // as is the case for dylib stubs, return None (no error). uint64_t CFHeaderOffset = DyldChainedFixups.dataoff; - std::vector Targets; if (CFHeaderOffset == 0) - return Targets; + return None; // Load the dyld chained fixups header. const char* CFHeaderPtr = getPtr(*this, CFHeaderOffset); @@ -4803,6 +4804,35 @@ Twine("bad chained fixups: unknown imports format: ") + Twine(CFHeader.imports_format)); + // Validate the image format. + // + // Load the image starts. + uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset); + if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) { + return malformedError(Twine("bad chained fixups: image starts offset ") + + Twine(CFHeader.starts_offset) + + " overlaps with chained fixups header"); + } + uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize; + if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) > + EndOffset) { + return malformedError(Twine("bad chained fixups: image starts end ") + + Twine(CFImageStartsOffset + + sizeof(MachO::dyld_chained_starts_in_image)) + + " extends past end " + Twine(EndOffset)); + } + + return CFHeader; +} + +Expected> +MachOObjectFile::getDyldChainedFixupTargets() const { + auto CFHeaderOrErr = getChainedFixupsHeader(); + if (!CFHeaderOrErr) + return CFHeaderOrErr.takeError(); + std::vector Targets; + if (!(*CFHeaderOrErr)) + return Targets; return Targets; } Index: llvm/test/Object/AArch64/chained-fixups-header.test =================================================================== --- llvm/test/Object/AArch64/chained-fixups-header.test +++ llvm/test/Object/AArch64/chained-fixups-header.test @@ -9,3 +9,15 @@ RUN: | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \ RUN: | FileCheck %s --check-prefix=HEADER2 HEADER2: truncated or malformed object (bad chained fixups: unknown imports format: 171) + +RUN: cat %p/../Inputs/MachO/chained-fixups.yaml \ +RUN: | sed 's/20000000/01000000/' \ +RUN: | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \ +RUN: | FileCheck %s --check-prefix=HEADER3 +HEADER3: truncated or malformed object (bad chained fixups: image starts offset 1 overlaps with chained fixups header) + +RUN: cat %p/../Inputs/MachO/chained-fixups.yaml \ +RUN: | sed 's/20000000/FF000000/' \ +RUN: | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \ +RUN: | FileCheck %s --check-prefix=HEADER4 +HEADER4: truncated or malformed object (bad chained fixups: image starts end 33031 extends past end 32856)