More additional error checks for invalid Mach-O files when

the offsets and sizes of an element of the file overlaps with
another element in the Mach-O file.

This shows the approach to this testing for three elements
and contains for tests for their overlap.  Checking for all the
remain elements will be added next.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285632 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kevin Enderby 2016-10-31 20:29:48 +00:00
parent 7e057dcd4e
commit e9885e072b
4 changed files with 58 additions and 5 deletions

View File

@ -27,6 +27,7 @@
#include <cctype>
#include <cstring>
#include <limits>
#include <list>
using namespace llvm;
using namespace object;
@ -216,6 +217,42 @@ static void parseHeader(const MachOObjectFile *Obj, T &Header,
Err = HeaderOrErr.takeError();
}
// This is used to check for overlapping of Mach-O elements.
struct MachOElement {
uint64_t Offset;
uint64_t Size;
const char *Name;
};
static Error checkOverlappingElement(std::list<MachOElement> &Elements,
uint64_t Offset, uint64_t Size,
const char *Name) {
if (Size == 0)
return Error::success();
for (auto it=Elements.begin() ; it != Elements.end(); ++it) {
auto E = *it;
if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||
(Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||
(Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))
return malformedError(Twine(Name) + " at offset " + Twine(Offset) +
" with a size of " + Twine(Size) + ", overlaps " +
E.Name + " at offset " + Twine(E.Offset) + " with "
"a size of " + Twine(E.Size));
auto nt = it;
nt++;
if (nt != Elements.end()) {
auto N = *nt;
if (Offset + Size <= N.Offset) {
Elements.insert(nt, {Offset, Size, Name});
return Error::success();
}
}
}
Elements.push_back({Offset, Size, Name});
return Error::success();
}
// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
// sections to \param Sections, and optionally sets
// \param IsPageZeroSegment to true.
@ -331,7 +368,8 @@ static Error parseSegmentLoadCommand(
static Error checkSymtabCommand(const MachOObjectFile *Obj,
const MachOObjectFile::LoadCommandInfo &Load,
uint32_t LoadCommandIndex,
const char **SymtabLoadCmd) {
const char **SymtabLoadCmd,
std::list<MachOElement> &Elements) {
if (Load.C.cmdsize < sizeof(MachO::symtab_command))
return malformedError("load command " + Twine(LoadCommandIndex) +
" LC_SYMTAB cmdsize too small");
@ -347,21 +385,25 @@ static Error checkSymtabCommand(const MachOObjectFile *Obj,
return malformedError("symoff field of LC_SYMTAB command " +
Twine(LoadCommandIndex) + " extends past the end "
"of the file");
uint64_t BigSize = Symtab.nsyms;
uint64_t SymtabSize = Symtab.nsyms;
const char *struct_nlist_name;
if (Obj->is64Bit()) {
BigSize *= sizeof(MachO::nlist_64);
SymtabSize *= sizeof(MachO::nlist_64);
struct_nlist_name = "struct nlist_64";
} else {
BigSize *= sizeof(MachO::nlist);
SymtabSize *= sizeof(MachO::nlist);
struct_nlist_name = "struct nlist";
}
uint64_t BigSize = SymtabSize;
BigSize += Symtab.symoff;
if (BigSize > FileSize)
return malformedError("symoff field plus nsyms field times sizeof(" +
Twine(struct_nlist_name) + ") of LC_SYMTAB command " +
Twine(LoadCommandIndex) + " extends past the end "
"of the file");
if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,
"symbol table"))
return Err;
if (Symtab.stroff > FileSize)
return malformedError("stroff field of LC_SYMTAB command " +
Twine(LoadCommandIndex) + " extends past the end "
@ -372,6 +414,9 @@ static Error checkSymtabCommand(const MachOObjectFile *Obj,
return malformedError("stroff field plus strsize field of LC_SYMTAB "
"command " + Twine(LoadCommandIndex) + " extends "
"past the end of the file");
if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,
Symtab.strsize, "string table"))
return Err;
*SymtabLoadCmd = Load.Ptr;
return Error::success();
}
@ -977,6 +1022,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
"object file's mach header");
return;
}
std::list<MachOElement> Elements;
Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});
uint32_t LoadCommandCount = getHeader().ncmds;
LoadCommandInfo Load;
@ -1023,7 +1070,7 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
}
LoadCommands.push_back(Load);
if (Load.C.cmd == MachO::LC_SYMTAB) {
if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd)))
if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd, Elements)))
return;
} else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
if ((Err = checkDysymtabCommand(this, Load, I, &DysymtabLoadCmd)))

Binary file not shown.

Binary file not shown.

View File

@ -433,3 +433,9 @@ INVALID-FVMFILE-OBSOLETE: macho-invalid-fvmfile-obsolete': truncated or malforme
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-prepage-obsolete 2>&1 | FileCheck -check-prefix INVALID-PREPAGE-OBSOLETE %s
INVALID-PREPAGE-OBSOLETE: macho-invalid-prepage-obsolete': truncated or malformed object (load command 0 for cmd value of: 10 is obsolete and not supported)
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-overlap 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-OVERLAP %s
INVALID-SYMTAB-OVERLAP: macho-invalid-symtab-overlap': truncated or malformed object (symbol table at offset 8 with a size of 12, overlaps Mach-O headers at offset 0 with a size of 52)
RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-strtab-overlap 2>&1 | FileCheck -check-prefix INVALID-STRTAB-OVERLAP %s
INVALID-STRTAB-OVERLAP: macho-invalid-strtab-overlap': truncated or malformed object (string table at offset 60 with a size of 16, overlaps symbol table at offset 52 with a size of 12)