[llvm] bbaeb1e - Validate chained fixup image formats
Adrian Prantl via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 25 13:04:25 PST 2022
Author: Adrian Prantl
Date: 2022-02-25T13:04:00-08:00
New Revision: bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7
URL: https://github.com/llvm/llvm-project/commit/bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7
DIFF: https://github.com/llvm/llvm-project/commit/bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7.diff
LOG: 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
Added:
Modified:
llvm/include/llvm/BinaryFormat/MachO.h
llvm/include/llvm/Object/MachO.h
llvm/lib/Object/MachOObjectFile.cpp
llvm/test/Object/AArch64/chained-fixups-header.test
Removed:
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h
index 9850ba9c4d1cb..7e38c1342e321 100644
--- a/llvm/include/llvm/BinaryFormat/MachO.h
+++ b/llvm/include/llvm/BinaryFormat/MachO.h
@@ -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) {
diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h
index de911c005b53d..c248c9d0dc032 100644
--- a/llvm/include/llvm/Object/MachO.h
+++ b/llvm/include/llvm/Object/MachO.h
@@ -683,6 +683,9 @@ class MachOObjectFile : public ObjectFile {
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;
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 5d6e237c8a99a..a3e051664223b 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -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;
}
diff --git a/llvm/test/Object/AArch64/chained-fixups-header.test b/llvm/test/Object/AArch64/chained-fixups-header.test
index 9a97a719aa8f8..9eebd15384d21 100644
--- a/llvm/test/Object/AArch64/chained-fixups-header.test
+++ b/llvm/test/Object/AArch64/chained-fixups-header.test
@@ -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)
More information about the llvm-commits
mailing list