forked from OSchip/llvm-project
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 llvm-svn: 226219
This commit is contained in:
parent
d237ae4b2f
commit
4013950034
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,51 @@
|
|||
// No crash, might not be totally invalid
|
||||
RUN: llvm-objdump -private-headers %p/Inputs/macho-invalid-zero-ncmds
|
||||
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-incomplete-load-command 2>&1 \
|
||||
RUN: | FileCheck -check-prefix INCOMPLETE-LOADC %s
|
||||
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-load-command 2>&1 \
|
||||
RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-load-command 2>&1 \
|
||||
RUN: | FileCheck -check-prefix SMALL-LOADC-SIZE %s
|
||||
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-segment-load-command 2>&1 \
|
||||
RUN: | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-segment-load-command 2>&1 \
|
||||
RUN: | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s
|
||||
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-no-size-for-sections 2>&1 \
|
||||
RUN: | FileCheck -check-prefix TOO-MANY-SECTS %s
|
||||
RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-no-size-for-sections 2>&1 \
|
||||
RUN: | FileCheck -check-prefix TOO-MANY-SECTS %s
|
||||
|
||||
RUN: not llvm-objdump -t %p/Inputs/macho-invalid-bad-symbol-index 2>&1 \
|
||||
RUN: | FileCheck -check-prefix BAD-SYMBOL %s
|
||||
|
||||
RUN: not llvm-objdump -t %p/Inputs/macho-invalid-symbol-name-past-eof 2>&1 \
|
||||
RUN: | FileCheck -check-prefix NAME-PAST-EOF %s
|
||||
|
||||
RUN: not llvm-objdump -t %p/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName 2>&1 \
|
||||
RUN: | FileCheck -check-prefix INVALID-SECTION-IDX-SEG-NAME %s
|
||||
|
||||
RUN: not llvm-nm %p/Inputs/macho-invalid-section-index-getSectionRawName 2>&1 \
|
||||
RUN: | FileCheck -check-prefix INVALID-SECTION-IDX-SECT-NAME %s
|
||||
|
||||
RUN: not llvm-objdump -t %p/Inputs/macho-invalid-getsection-index 2>&1 \
|
||||
RUN: | FileCheck -check-prefix INVALID-SECTION-IDX-GETSECT %s
|
||||
|
||||
RUN: not llvm-objdump -t %p/Inputs/macho64-invalid-getsection-index 2>&1 \
|
||||
RUN: | FileCheck -check-prefix INVALID-SECTION-IDX-GETSECT64 %s
|
||||
|
||||
|
||||
SMALL-LOADC-SIZE: Load command with size < 8 bytes
|
||||
SMALL-SEGLOADC-SIZE: Segment load command size is too small
|
||||
INCOMPLETE-LOADC: Malformed MachO file
|
||||
TOO-MANY-SECTS: Number of sections too large for size of load command
|
||||
BAD-SYMBOL: Requested symbol index is out of range
|
||||
NAME-PAST-EOF: Symbol name entry points past end of file
|
||||
|
||||
INVALID-SECTION-IDX-SEG-NAME: getSectionRawFinalSegmentName: Invalid section index
|
||||
INVALID-SECTION-IDX-SECT-NAME: getSectionRawName: Invalid section index
|
||||
INVALID-SECTION-IDX-GETSECT: getSection: Invalid section index
|
||||
INVALID-SECTION-IDX-GETSECT64: getSection64: Invalid section index
|
|
@ -1,9 +0,0 @@
|
|||
RUN: llvm-objdump -private-headers %p/Inputs/macho-zero-ncmds \
|
||||
RUN: | FileCheck %s -check-prefix A
|
||||
|
||||
// Check that we don't get an infinite loop if ncmds = 0
|
||||
A: file format Mach-O 64-bit unknown
|
||||
A: Mach header
|
||||
A: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
|
||||
A: MH_MAGIC_64 0x00 OBJECT 0 0 0x00000000
|
||||
|
Loading…
Reference in New Issue