forked from OSchip/llvm-project
Validate chained fixup image formats
This is part of a series of patches to upstream support for Mach-O chained fixups. Differential Revision: https://reviews.llvm.org/D113725
This commit is contained in:
parent
2cd9a86da5
commit
bbaeb1ee0e
|
@ -1015,6 +1015,14 @@ struct dyld_chained_fixups_header {
|
|||
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) {
|
||||
|
|
|
@ -683,6 +683,9 @@ public:
|
|||
ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
|
||||
ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
|
||||
ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
|
||||
/// If the optional is None, no header was found, but the object was well-formed.
|
||||
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
||||
getChainedFixupsHeader() const;
|
||||
Expected<std::vector<ChainedFixupTarget>> getDyldChainedFixupTargets() const;
|
||||
ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
|
||||
SmallVector<uint64_t> getFunctionStarts() const;
|
||||
|
|
|
@ -3259,13 +3259,13 @@ MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
|
|||
bool Parse)
|
||||
: MachOAbstractFixupEntry(E, O) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4763,11 +4763,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
|
|||
return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
|
||||
}
|
||||
|
||||
Expected<std::vector<ChainedFixupTarget>>
|
||||
MachOObjectFile::getDyldChainedFixupTargets() const {
|
||||
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
||||
MachOObjectFile::getChainedFixupsHeader() const {
|
||||
// Load the dyld chained fixups load command.
|
||||
if (!DyldChainedFixupsLoadCmd)
|
||||
return std::vector<ChainedFixupTarget>();
|
||||
return llvm::None;
|
||||
auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>(
|
||||
*this, DyldChainedFixupsLoadCmd);
|
||||
if (!DyldChainedFixupsOrErr)
|
||||
|
@ -4775,11 +4775,10 @@ MachOObjectFile::getDyldChainedFixupTargets() const {
|
|||
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<ChainedFixupTarget> Targets;
|
||||
if (CFHeaderOffset == 0)
|
||||
return Targets;
|
||||
return DyldChainedFixupsOrErr.takeError();
|
||||
|
||||
// Load the dyld chained fixups header.
|
||||
const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
|
||||
|
@ -4798,6 +4797,35 @@ MachOObjectFile::getDyldChainedFixupTargets() const {
|
|||
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<std::vector<ChainedFixupTarget>>
|
||||
MachOObjectFile::getDyldChainedFixupTargets() const {
|
||||
auto CFHeaderOrErr = getChainedFixupsHeader();
|
||||
if (!CFHeaderOrErr)
|
||||
return CFHeaderOrErr.takeError();
|
||||
std::vector<ChainedFixupTarget> Targets;
|
||||
if (!(*CFHeaderOrErr))
|
||||
return Targets;
|
||||
return Targets;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,3 +10,15 @@ RUN: | sed 's/1000000010000000/1000000AB0000000/' \
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue