mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:50:30 +00:00
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
9510b7f6fd
commit
f8083bfc50
@ -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]);
|
||||
}
|
||||
|
||||
|
BIN
test/Object/Inputs/macho-invalid-bad-symbol-index
Normal file
BIN
test/Object/Inputs/macho-invalid-bad-symbol-index
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-getsection-index
Normal file
BIN
test/Object/Inputs/macho-invalid-getsection-index
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-no-size-for-sections
Normal file
BIN
test/Object/Inputs/macho-invalid-no-size-for-sections
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-section-index-getSectionRawName
Normal file
BIN
test/Object/Inputs/macho-invalid-section-index-getSectionRawName
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-symbol-name-past-eof
Normal file
BIN
test/Object/Inputs/macho-invalid-symbol-name-past-eof
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-too-small-load-command
Normal file
BIN
test/Object/Inputs/macho-invalid-too-small-load-command
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho-invalid-too-small-segment-load-command
Normal file
BIN
test/Object/Inputs/macho-invalid-too-small-segment-load-command
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho64-invalid-getsection-index
Normal file
BIN
test/Object/Inputs/macho64-invalid-getsection-index
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho64-invalid-incomplete-load-command
Normal file
BIN
test/Object/Inputs/macho64-invalid-incomplete-load-command
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho64-invalid-no-size-for-sections
Normal file
BIN
test/Object/Inputs/macho64-invalid-no-size-for-sections
Normal file
Binary file not shown.
BIN
test/Object/Inputs/macho64-invalid-too-small-load-command
Normal file
BIN
test/Object/Inputs/macho64-invalid-too-small-load-command
Normal file
Binary file not shown.
Binary file not shown.
51
test/Object/macho-invalid.test
Normal file
51
test/Object/macho-invalid.test
Normal file
@ -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
Block a user