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:
Adrian Prantl 2022-02-25 11:43:44 -08:00
parent 2cd9a86da5
commit bbaeb1ee0e
4 changed files with 64 additions and 13 deletions

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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)