summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp113
1 files changed, 96 insertions, 17 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 863081fbd4c..f34e68721c0 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -219,19 +219,19 @@ static void parseHeader(const MachOObjectFile *Obj, T &Header,
// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
// sections to \param Sections, and optionally sets
// \param IsPageZeroSegment to true.
-template <typename SegmentCmd>
+template <typename Segment, typename Section>
static Error parseSegmentLoadCommand(
const MachOObjectFile *Obj, const MachOObjectFile::LoadCommandInfo &Load,
SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment,
- uint32_t LoadCommandIndex, const char *CmdName) {
- const unsigned SegmentLoadSize = sizeof(SegmentCmd);
+ uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders) {
+ const unsigned SegmentLoadSize = sizeof(Segment);
if (Load.C.cmdsize < SegmentLoadSize)
return malformedError("load command " + Twine(LoadCommandIndex) +
" " + CmdName + " cmdsize too small");
- if (auto SegOrErr = getStructOrErr<SegmentCmd>(Obj, Load.Ptr)) {
- SegmentCmd S = SegOrErr.get();
- const unsigned SectionSize =
- Obj->is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section);
+ if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) {
+ Segment S = SegOrErr.get();
+ const unsigned SectionSize = sizeof(Section);
+ uint64_t FileSize = Obj->getData().size();
if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
return malformedError("load command " + Twine(LoadCommandIndex) +
@@ -240,12 +240,88 @@ static Error parseSegmentLoadCommand(
for (unsigned J = 0; J < S.nsects; ++J) {
const char *Sec = getSectionPtr(Obj, Load, J);
Sections.push_back(Sec);
+ Section s = getStruct<Section>(Obj, Sec);
+ if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj->getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ s.offset > FileSize)
+ return malformedError("offset field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj->getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ S.fileoff == 0 && s.offset < SizeOfHeaders && s.size != 0)
+ return malformedError("offset field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " not past the headers of the file");
+ uint64_t BigSize = s.offset;
+ BigSize += s.size;
+ if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj->getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ BigSize > FileSize)
+ return malformedError("offset field plus size field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj->getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ s.size > S.filesize)
+ return malformedError("size field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " greater than the segment");
+ if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj->getHeader().filetype != MachO::MH_DSYM &&
+ s.size != 0 && s.addr < S.vmaddr)
+ return malformedError("addr field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " less than the segment's vmaddr");
+ BigSize = s.addr;
+ BigSize += s.size;
+ uint64_t BigEnd = S.vmaddr;
+ BigEnd += S.vmsize;
+ if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd)
+ return malformedError("addr field plus size of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) + " greater than than "
+ "the segment's vmaddr plus vmsize");
+ if (s.reloff > FileSize)
+ return malformedError("reloff field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ BigSize = s.nreloc;
+ BigSize *= sizeof(struct MachO::relocation_info);
+ BigSize += s.reloff;
+ if (BigSize > FileSize)
+ return malformedError("reloff field plus nreloc field times sizeof("
+ "struct relocation_info) of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " extends past the end of the file");
}
- uint64_t FileSize = Obj->getData().size();
if (S.fileoff > FileSize)
return malformedError("load command " + Twine(LoadCommandIndex) +
" fileoff field in " + CmdName +
" extends past the end of the file");
+ uint64_t BigSize = S.fileoff;
+ BigSize += S.filesize;
+ if (BigSize > FileSize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " fileoff field plus filesize field in " +
+ CmdName + " extends past the end of the file");
+ if (S.vmsize != 0 && S.filesize > S.vmsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " fileoff field in " + CmdName +
+ " greater than vmsize field");
IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
} else
return SegOrErr.takeError();
@@ -273,18 +349,18 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr),
HasPageZeroSegment(false) {
ErrorAsOutParameter ErrAsOutParam(&Err);
- uint64_t BigSize;
+ uint64_t SizeOfHeaders;
if (is64Bit()) {
parseHeader(this, Header64, Err);
- BigSize = sizeof(MachO::mach_header_64);
+ SizeOfHeaders = sizeof(MachO::mach_header_64);
} else {
parseHeader(this, Header, Err);
- BigSize = sizeof(MachO::mach_header);
+ SizeOfHeaders = sizeof(MachO::mach_header);
}
if (Err)
return;
- BigSize += getHeader().sizeofcmds;
- if (getData().data() + BigSize > getData().end()) {
+ SizeOfHeaders += getHeader().sizeofcmds;
+ if (getData().data() + SizeOfHeaders > getData().end()) {
Err = malformedError("load commands extend past the end of the file");
return;
}
@@ -366,13 +442,16 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
}
UuidLoadCmd = Load.Ptr;
} else if (Load.C.cmd == MachO::LC_SEGMENT_64) {
- if ((Err = parseSegmentLoadCommand<MachO::segment_command_64>(
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command_64,
+ MachO::section_64>(
this, Load, Sections, HasPageZeroSegment, I,
- "LC_SEGMENT_64")))
+ "LC_SEGMENT_64", SizeOfHeaders)))
return;
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
- if ((Err = parseSegmentLoadCommand<MachO::segment_command>(
- this, Load, Sections, HasPageZeroSegment, I, "LC_SEGMENT")))
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command,
+ MachO::section>(
+ this, Load, Sections, HasPageZeroSegment, I,
+ "LC_SEGMENT", SizeOfHeaders)))
return;
} else if (Load.C.cmd == MachO::LC_LOAD_DYLIB ||
Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
OpenPOWER on IntegriCloud