From e9885e072be0fc74531ffc004f5b4b8cac258f08 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Mon, 31 Oct 2016 20:29:48 +0000 Subject: [PATCH] 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 --- lib/Object/MachOObjectFile.cpp | 57 ++++++++++++++++-- .../Inputs/macho-invalid-strtab-overlap | Bin 0 -> 80 bytes .../Inputs/macho-invalid-symtab-overlap | Bin 0 -> 52 bytes test/Object/macho-invalid.test | 6 ++ 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 test/Object/Inputs/macho-invalid-strtab-overlap create mode 100644 test/Object/Inputs/macho-invalid-symtab-overlap diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 8bb55175efa..724056f492a 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -27,6 +27,7 @@ #include #include #include +#include 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 &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 &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 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))) diff --git a/test/Object/Inputs/macho-invalid-strtab-overlap b/test/Object/Inputs/macho-invalid-strtab-overlap new file mode 100644 index 0000000000000000000000000000000000000000..279728acce9ce9a7c74a31eca762df4ba9c4b519 GIT binary patch literal 80 vcmX^2>+L^w1_lOZAZCPO2_OvuOh61`n*cFL&IX7DfS3cy2U2j52xS2PNC5=h literal 0 HcmV?d00001 diff --git a/test/Object/Inputs/macho-invalid-symtab-overlap b/test/Object/Inputs/macho-invalid-symtab-overlap new file mode 100644 index 0000000000000000000000000000000000000000..9fc5b8e9f51376e97dd843c24dd790bbc40323ff GIT binary patch literal 52 icmX^2>+L^w1_lOZAZCPO2_OvuOh61`a{w_&4h8_iegpde literal 0 HcmV?d00001 diff --git a/test/Object/macho-invalid.test b/test/Object/macho-invalid.test index f95eebc315a..105bfb075f3 100644 --- a/test/Object/macho-invalid.test +++ b/test/Object/macho-invalid.test @@ -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) -- 2.40.0