From 34a869ca6c5e89bd36aa2c42715e319fd8e69fbc Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Mon, 14 Nov 2016 20:57:04 +0000 Subject: [PATCH] Add a checkSymbolTable() method to the MachOObjectFile class. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The philosophy of the error checking in libObject for Mach-O files is that the constructor will check the load commands so for their tables the offsets and sizes are properly contained in the file. But there is no checking of the entries of any of the tables. For the contents of the tables themselves the methods accessing the contents of the entries return errors as needed. In some cases this however makes it difficult or cumbersome to produce a good error message which would include the tool name, file name, archive member, and name of the architecture of a slice of a universal file the error occurred in. So idea is that there will be a method to check a table which can be called up front before using it allowing a good error message to be produced before a table is used. And if only verification of the Mach-O file and its tables are wanted a new possible method checkAllTables() could be added to call all of the methods to check all the tables at some time when such methods exist. The checkSymbolTable() is the first of such methods to check one of the Mach-O file tables. This method initially will used in llvm-objdump’s DisassembleMachO() routine before it gets the section and symbol information. As if there are problems with the symbol table currently the error is first encountered by the bool operator() in the SymbolSorter() struct which passed to std::sort(). In this case there is no context as to the file name the symbol which results a poor error message: LLVM ERROR: truncated or malformed object (bad string index: 22 for symbol at index 1) with the added call to the checkSymbolTable() method the error message includes the tool name and file name: llvm-objdump: 'macho-invalid-symbol-strx': truncated or malformed object (bad string table index: 22 past the end of string table, for symbol at index 1) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286887 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/MachO.h | 2 + lib/Object/MachOObjectFile.cpp | 68 ++++++++++++++++++ .../X86/Inputs/macho-invalid-symbol-indr | Bin 0 -> 260 bytes .../Inputs/macho-invalid-symbol-lib_ordinal | Bin 0 -> 304 bytes .../X86/Inputs/macho-invalid-symbol-nsect | Bin 0 -> 424 bytes .../X86/Inputs/macho-invalid-symbol-strx | Bin 0 -> 260 bytes .../llvm-objdump/X86/malformed-machos.test | 12 ++++ tools/llvm-objdump/MachODump.cpp | 3 + 8 files changed, 85 insertions(+) create mode 100644 test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-indr create mode 100644 test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-lib_ordinal create mode 100644 test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-nsect create mode 100644 test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-strx diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index a26a2ef7dfe..b0f106f89c0 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -203,6 +203,8 @@ public: Expected getSymbolName(DataRefImpl Symb) const override; // MachO specific. + Error checkSymbolTable() const; + std::error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const; unsigned getSectionType(SectionRef Sec) const; diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 6650ace0845..cd0c2006f00 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1501,6 +1501,74 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, Err = Error::success(); } +Error MachOObjectFile::checkSymbolTable() const { + uint32_t Flags = 0; + if (is64Bit()) { + MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64(); + Flags = H_64.flags; + } else { + MachO::mach_header H = MachOObjectFile::getHeader(); + Flags = H.flags; + } + uint8_t NType = 0; + uint8_t NSect = 0; + uint16_t NDesc = 0; + uint32_t NStrx = 0; + uint64_t NValue = 0; + uint32_t SymbolIndex = 0; + MachO::symtab_command S = getSymtabLoadCommand(); + for (const SymbolRef &Symbol : symbols()) { + DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); + if (is64Bit()) { + MachO::nlist_64 STE_64 = getSymbol64TableEntry(SymDRI); + NType = STE_64.n_type; + NSect = STE_64.n_sect; + NDesc = STE_64.n_desc; + NStrx = STE_64.n_strx; + NValue = STE_64.n_value; + } else { + MachO::nlist STE = getSymbolTableEntry(SymDRI); + NType = STE.n_type; + NType = STE.n_type; + NSect = STE.n_sect; + NDesc = STE.n_desc; + NStrx = STE.n_strx; + NValue = STE.n_value; + } + if ((NType & MachO::N_STAB) == 0 && + (NType & MachO::N_TYPE) == MachO::N_SECT) { + if (NSect == 0 || NSect > Sections.size()) + return malformedError("bad section index: " + Twine((int)NSect) + + " for symbol at index " + Twine(SymbolIndex)); + } + if ((NType & MachO::N_STAB) == 0 && + (NType & MachO::N_TYPE) == MachO::N_INDR) { + if (NValue >= S.strsize) + return malformedError("bad n_value: " + Twine((int)NValue) + " past " + "the end of string table, for N_INDR symbol at " + "index " + Twine(SymbolIndex)); + } + if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && + (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || + (NType & MachO::N_TYPE) == MachO::N_PBUD)) { + uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); + if (LibraryOrdinal != 0 && + LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && + LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && + LibraryOrdinal - 1 >= Libraries.size() ) { + return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) + + " for symbol at index " + Twine(SymbolIndex)); + } + } + if (NStrx >= S.strsize) + return malformedError("bad string table index: " + Twine((int)NStrx) + + " past the end of string table, for symbol at " + "index " + Twine(SymbolIndex)); + SymbolIndex++; + } + return Error::success(); +} + void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const { unsigned SymbolTableEntrySize = is64Bit() ? sizeof(MachO::nlist_64) : diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-indr b/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-indr new file mode 100644 index 0000000000000000000000000000000000000000..67751b7f12e28fd1f9d2c5a774b8aed1e8d83abc GIT binary patch literal 260 zcmX^2>+L^w1_lOZAZCK%DL@(o7=gG3h~wkk{QW@!NI(I|-T=fP8U{e>K_EUpDX|E` zgz|CgM^Xl2Ho*8Gw@3i-1t12w?F$eK0PzF@fCH$8ALtN}T0S7=24XQF<^f`u`+!U^ LNCc9l44Di7i*g~~ literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-lib_ordinal b/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-lib_ordinal new file mode 100644 index 0000000000000000000000000000000000000000..d3b54701a55777fadaac69655908e6a2003386d7 GIT binary patch literal 304 zcmX^2>+L^w1_lOZAZCKn2Y_?~5HkXC4G_o2yZQSAX=I=P&EVgLZAnkP#D literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-nsect b/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-nsect new file mode 100644 index 0000000000000000000000000000000000000000..3ee21c4b024226b8d0ab8bf7ee40f698df4c25c4 GIT binary patch literal 424 zcmX^2>+L^w1_lOZAZCK%DL@(o7=gG3h~wkk{QW@!NI(I|-T=fP8U{e>K_EUpDX|E` zgz|CgM^c8u1i3{5h%W#!$ZcPMSOAC#0S=%7exO4@YWYCyL4wIE5Dn@WI^AUDkb(!{t4ZZOapAagO?2oxmbMgY!u6Y2l} literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-strx b/test/tools/llvm-objdump/X86/Inputs/macho-invalid-symbol-strx new file mode 100644 index 0000000000000000000000000000000000000000..4a6e56135db57af2b0cd23a66af7458cbecb16e7 GIT binary patch literal 260 zcmX^2>+L^w1_lOZAZCK%DL@(o7=gG3h~wkk{QW@!NI(I|-T=fP8U{e>K_EUpDX|E` zgz|CgM^Xl2Ho*8Gw@3i-1t12w?F$eK0PzF@fCH$8ALtN}S}`bF2uSk)G0c5HCKx0F J$x?<)1^|rZA?N@A literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/malformed-machos.test b/test/tools/llvm-objdump/X86/malformed-machos.test index 499c23e09d2..edd6a24177e 100644 --- a/test/tools/llvm-objdump/X86/malformed-machos.test +++ b/test/tools/llvm-objdump/X86/malformed-machos.test @@ -39,3 +39,15 @@ # RUN: | FileCheck -check-prefix=m0337 %s # m0337: mem-crup-0337.macho': truncated or malformed object (section relocation entries at offset 0 with a size of 512, overlaps Mach-O headers at offset 0 with a size of 2048) + +RUN: not llvm-objdump -macho -disassemble %p/Inputs/macho-invalid-symbol-nsect 2>&1 | FileCheck -check-prefix INVALID-SYMBOL-NSECT %s +INVALID-SYMBOL-NSECT: macho-invalid-symbol-nsect': truncated or malformed object (bad section index: 97 for symbol at index 1) + +RUN: not llvm-objdump -macho -disassemble %p/Inputs/macho-invalid-symbol-indr 2>&1 | FileCheck -check-prefix INVALID-SYMBOL-INDR %s +INVALID-SYMBOL-INDR: macho-invalid-symbol-indr': truncated or malformed object (bad n_value: 22 past the end of string table, for N_INDR symbol at index 1) + +RUN: not llvm-objdump -macho -disassemble %p/Inputs/macho-invalid-symbol-strx 2>&1 | FileCheck -check-prefix INVALID-SYMBOL-STRX %s +INVALID-SYMBOL-STRX: macho-invalid-symbol-strx': truncated or malformed object (bad string table index: 22 past the end of string table, for symbol at index 1) + +RUN: not llvm-objdump -macho -disassemble %p/Inputs/macho-invalid-symbol-lib_ordinal 2>&1 | FileCheck -check-prefix INVALID-SYMBOL-LIB_ORDINAL %s +INVALID-SYMBOL-LIB_ORDINAL: macho-invalid-symbol-lib_ordinal': truncated or malformed object (bad library ordinal: 7 for symbol at index 2) diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 929e70d8cb5..249ab7e90a3 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -6523,6 +6523,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, SmallVector FoundFns; uint64_t BaseSegmentAddress; + if (Error Err = MachOOF->checkSymbolTable()) + report_error(Filename, std::move(Err)); + getSectionsAndSymbols(MachOOF, Sections, Symbols, FoundFns, BaseSegmentAddress); -- 2.50.1