Report fatal errors instead of segfaulting/asserting on a few invalid accesses while reading MachO files.

Summary:
Shift an older “invalid file” test to get a consistent naming for these tests.

Bugs found by afl-fuzz

Reviewers: rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D6945

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226219 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Filipe Cabecinhas
2015-01-15 22:52:38 +00:00
parent 07e3f81e93
commit 0183477621
17 changed files with 97 additions and 17 deletions

View File

@ -38,8 +38,12 @@ namespace {
};
}
template<typename T>
template <typename T>
static T getStruct(const MachOObjectFile *O, const char *P) {
// Don't read before the beginning or past the end of the file
if (P < O->getData().begin() || P + sizeof(T) > O->getData().end())
report_fatal_error("Malformed MachO file.");
T Cmd;
memcpy(&Cmd, P, sizeof(T));
if (O->isLittleEndian() != sys::IsLittleEndianHost)
@ -47,15 +51,26 @@ static T getStruct(const MachOObjectFile *O, const char *P) {
return Cmd;
}
template <typename SegmentCmd>
static uint32_t getSegmentLoadCommandNumSections(const SegmentCmd &S,
uint32_t Cmdsize) {
const unsigned SectionSize = sizeof(SegmentCmd);
if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
S.nsects * SectionSize > Cmdsize - sizeof(S))
report_fatal_error(
"Number of sections too large for size of load command.");
return S.nsects;
}
static uint32_t
getSegmentLoadCommandNumSections(const MachOObjectFile *O,
const MachOObjectFile::LoadCommandInfo &L) {
if (O->is64Bit()) {
MachO::segment_command_64 S = O->getSegment64LoadCommand(L);
return S.nsects;
}
MachO::segment_command S = O->getSegmentLoadCommand(L);
return S.nsects;
if (O->is64Bit())
return getSegmentLoadCommandNumSections(O->getSegment64LoadCommand(L),
L.C.cmdsize);
return getSegmentLoadCommandNumSections(O->getSegmentLoadCommand(L),
L.C.cmdsize);
}
static bool isPageZeroSegment(const MachOObjectFile *O,
@ -281,6 +296,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
}
UuidLoadCmd = Load.Ptr;
} else if (Load.C.cmd == SegmentLoadType) {
const unsigned SegmentLoadSize = this->is64Bit()
? sizeof(MachO::segment_command_64)
: sizeof(MachO::segment_command);
if (Load.C.cmdsize < SegmentLoadSize)
report_fatal_error("Segment load command size is too small.");
uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load);
for (unsigned J = 0; J < NumSections; ++J) {
const char *Sec = getSectionPtr(this, Load, J);
@ -315,6 +336,8 @@ std::error_code MachOObjectFile::getSymbolName(DataRefImpl Symb,
StringRef StringTable = getStringTableData();
MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb);
const char *Start = &StringTable.data()[Entry.n_strx];
if (Start >= getData().end())
report_fatal_error("Symbol name entry points past end of file.");
Res = StringRef(Start);
return object_error::success;
}
@ -1204,7 +1227,8 @@ basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
return basic_symbol_iterator(SymbolRef(DRI, this));
MachO::symtab_command Symtab = getSymtabLoadCommand();
assert(Index < Symtab.nsyms && "Requested symbol index is out of range.");
if (Index >= Symtab.nsyms)
report_fatal_error("Requested symbol index is out of range.");
unsigned SymbolTableEntrySize =
is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Symtab.symoff));
@ -2108,6 +2132,8 @@ MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
ArrayRef<char>
MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
if (Sec.d.a >= Sections.size())
report_fatal_error("getSectionRawName: Invalid section index");
const section_base *Base =
reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
return makeArrayRef(Base->sectname);
@ -2115,6 +2141,8 @@ MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
ArrayRef<char>
MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
if (Sec.d.a >= Sections.size())
report_fatal_error("getSectionRawFinalSegmentName: Invalid section index");
const section_base *Base =
reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
return makeArrayRef(Base->segname);
@ -2205,6 +2233,8 @@ MachOObjectFile::getFirstLoadCommandInfo() const {
sizeof(MachO::mach_header);
Load.Ptr = getPtr(this, HeaderSize);
Load.C = getStruct<MachO::load_command>(this, Load.Ptr);
if (Load.C.cmdsize < 8)
report_fatal_error("Load command with size < 8 bytes.");
return Load;
}
@ -2213,14 +2243,22 @@ MachOObjectFile::getNextLoadCommandInfo(const LoadCommandInfo &L) const {
MachOObjectFile::LoadCommandInfo Next;
Next.Ptr = L.Ptr + L.C.cmdsize;
Next.C = getStruct<MachO::load_command>(this, Next.Ptr);
if (Next.C.cmdsize < 8)
report_fatal_error("Load command with size < 8 bytes.");
return Next;
}
MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
// TODO: What if Sections.size() == 0?
if (DRI.d.a >= Sections.size())
report_fatal_error("getSection: Invalid section index.");
return getStruct<MachO::section>(this, Sections[DRI.d.a]);
}
MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
// TODO: What if Sections.size() == 0?
if (DRI.d.a >= Sections.size())
report_fatal_error("getSection64: Invalid section index.");
return getStruct<MachO::section_64>(this, Sections[DRI.d.a]);
}