Next set of additional error checks for invalid Mach-O files for bad LC_SYMTAB’s.
authorKevin Enderby <enderby@apple.com>
Fri, 26 Aug 2016 19:34:07 +0000 (19:34 +0000)
committerKevin Enderby <enderby@apple.com>
Fri, 26 Aug 2016 19:34:07 +0000 (19:34 +0000)
This contains the missing checks for LC_SYMTAB load command fields.

llvm-svn: 279854

llvm/lib/Object/MachOObjectFile.cpp
llvm/test/Object/Inputs/macho-invalid-symtab-bad-size [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-more-than-one [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-small [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-stroff [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-stroff-strsize [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-symoff [new file with mode: 0644]
llvm/test/Object/Inputs/macho-invalid-symtab-symoff-nsyms [new file with mode: 0644]
llvm/test/Object/macho-invalid.test

index 43e76a9..26fd9a6 100644 (file)
@@ -328,6 +328,55 @@ static Error parseSegmentLoadCommand(
   return Error::success();
 }
 
+static Error checkSymtabCommand(const MachOObjectFile *Obj,
+                                const MachOObjectFile::LoadCommandInfo &Load,
+                                uint32_t LoadCommandIndex,
+                                const char **SymtabLoadCmd) {
+  if (Load.C.cmdsize < sizeof(MachO::symtab_command))
+    return malformedError("load command " + Twine(LoadCommandIndex) +
+                          " LC_SYMTAB cmdsize too small");
+  if (*SymtabLoadCmd != nullptr)
+    return malformedError("more than one LC_SYMTAB command");
+  MachO::symtab_command Symtab =
+    getStruct<MachO::symtab_command>(Obj, Load.Ptr);
+  if (Symtab.cmdsize != sizeof(MachO::symtab_command))
+    return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) +
+                          " has incorrect cmdsize");
+  uint64_t FileSize = Obj->getData().size();
+  if (Symtab.symoff > FileSize)
+    return malformedError("symoff field of LC_SYMTAB command " +
+                          Twine(LoadCommandIndex) + " extends past the end "
+                          "of the file");
+  uint64_t BigSize = Symtab.nsyms;
+  const char *struct_nlist_name;
+  if (Obj->is64Bit()) {
+    BigSize *= sizeof(MachO::nlist_64);
+    struct_nlist_name = "struct nlist_64";
+  } else {
+    BigSize *= sizeof(MachO::nlist);
+    struct_nlist_name = "struct nlist";
+  }
+  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 (Symtab.stroff > FileSize)
+    return malformedError("stroff field of LC_SYMTAB command " +
+                          Twine(LoadCommandIndex) + " extends past the end "
+                          "of the file");
+  BigSize = Symtab.stroff;
+  BigSize += Symtab.strsize;
+  if (BigSize > FileSize)
+    return malformedError("stroff field plus strsize field of LC_SYMTAB "
+                          "command " + Twine(LoadCommandIndex) + " extends "
+                          "past the end of the file");
+
+  *SymtabLoadCmd = Load.Ptr;
+  return Error::success();
+}
+
 Expected<std::unique_ptr<MachOObjectFile>>
 MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
                         bool Is64Bits) {
@@ -398,12 +447,8 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
     }
     LoadCommands.push_back(Load);
     if (Load.C.cmd == MachO::LC_SYMTAB) {
-      // Multiple symbol tables
-      if (SymtabLoadCmd) {
-        Err = malformedError("Multiple symbol tables");
+      if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd)))
         return;
-      }
-      SymtabLoadCmd = Load.Ptr;
     } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
       // Multiple dynamic symbol tables
       if (DysymtabLoadCmd) {
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-bad-size b/llvm/test/Object/Inputs/macho-invalid-symtab-bad-size
new file mode 100644 (file)
index 0000000..12b6b89
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-bad-size differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-more-than-one b/llvm/test/Object/Inputs/macho-invalid-symtab-more-than-one
new file mode 100644 (file)
index 0000000..34088bf
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-more-than-one differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-small b/llvm/test/Object/Inputs/macho-invalid-symtab-small
new file mode 100644 (file)
index 0000000..cf2294d
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-small differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-stroff b/llvm/test/Object/Inputs/macho-invalid-symtab-stroff
new file mode 100644 (file)
index 0000000..44f7761
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-stroff differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-stroff-strsize b/llvm/test/Object/Inputs/macho-invalid-symtab-stroff-strsize
new file mode 100644 (file)
index 0000000..ea57737
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-stroff-strsize differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-symoff b/llvm/test/Object/Inputs/macho-invalid-symtab-symoff
new file mode 100644 (file)
index 0000000..c8251ac
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-symoff differ
diff --git a/llvm/test/Object/Inputs/macho-invalid-symtab-symoff-nsyms b/llvm/test/Object/Inputs/macho-invalid-symtab-symoff-nsyms
new file mode 100644 (file)
index 0000000..85d79e7
Binary files /dev/null and b/llvm/test/Object/Inputs/macho-invalid-symtab-symoff-nsyms differ
index 91e1ea7..c2f6ed2 100644 (file)
@@ -142,3 +142,24 @@ INVALID-SECTION-RELOFF: macho-invalid-section-reloff': truncated or malformed ob
 
 RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-reloff-nrelocs 2>&1 | FileCheck -check-prefix INVALID-SECTION-RELOFF-NRELOCS %s
 INVALID-SECTION-RELOFF-NRELOCS: macho-invalid-section-reloff-nrelocs': truncated or malformed object (reloff field plus nreloc field times sizeof(struct relocation_info) of section 0 in LC_SEGMENT command 0 extends past the end of the file)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-small 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-SMALL %s
+INVALID-SYMTAB-SMALL: macho-invalid-symtab-small': truncated or malformed object (load command 0 LC_SYMTAB cmdsize too small)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-more-than-one 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-MORE-THAN-ONE %s
+INVALID-SYMTAB-MORE-THAN-ONE: macho-invalid-symtab-more-than-one': truncated or malformed object (more than one LC_SYMTAB command)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-bad-size 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-BAD-SIZE %s
+INVALID-SYMTAB-BAD-SIZE: macho-invalid-symtab-bad-size': truncated or malformed object (LC_SYMTAB command 0 has incorrect cmdsize)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-symoff 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-SYMOFF %s
+INVALID-SYMTAB-SYMOFF: macho-invalid-symtab-symoff': truncated or malformed object (symoff field of LC_SYMTAB command 0 extends past the end of the file)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-symoff-nsyms 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-SYMOFF-NSYMS %s
+INVALID-SYMTAB-SYMOFF-NSYMS: macho-invalid-symtab-symoff-nsyms': truncated or malformed object (symoff field plus nsyms field times sizeof(struct nlist) of LC_SYMTAB command 0 extends past the end of the file)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-stroff 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-STROFF %s
+INVALID-SYMTAB-STROFF: macho-invalid-symtab-stroff': truncated or malformed object (stroff field of LC_SYMTAB command 0 extends past the end of the file)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-stroff-strsize 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-STROFF-STRSIZE %s
+INVALID-SYMTAB-STROFF-STRSIZE: macho-invalid-symtab-stroff-strsize': truncated or malformed object (stroff field plus strsize field of LC_SYMTAB command 0 extends past the end of the file)