[llvm] 0d54612 - [llvm-readelf] - Do not crash when the PT_INTERP has a broken offset.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Fri May 1 08:52:13 PDT 2020


Author: Georgii Rymar
Date: 2020-05-01T18:51:46+03:00
New Revision: 0d54612164519c874eecf5a1be68597b96410628

URL: https://github.com/llvm/llvm-project/commit/0d54612164519c874eecf5a1be68597b96410628
DIFF: https://github.com/llvm/llvm-project/commit/0d54612164519c874eecf5a1be68597b96410628.diff

LOG: [llvm-readelf] - Do not crash when the PT_INTERP has a broken offset.

We do not verify the p_offset of the PT_INTERP header and tool may
crash when a program interpreter name string goes past the end of the file.

Differential revision: https://reviews.llvm.org/D79013

Added: 
    

Modified: 
    llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test b/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test
index 324fa9fd7afe..cc3a38fb167b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test
@@ -1,7 +1,7 @@
 ## Check how llvm-readelf dumps program headers and prints sections to segments mapping.
 
 ## Check that -l, --program-headers and --segments are the same option.
-# RUN: yaml2obj -DBITS=32 -DMACHINE=EM_386 %s -o %t32.elf
+# RUN: yaml2obj --docnum=1 -DBITS=32 -DMACHINE=EM_386 %s -o %t32.elf
 # RUN: llvm-readelf -l %t32.elf 2>&1 > %t.readelf-l.txt
 # RUN: llvm-readelf --program-headers %t32.elf 2>&1 > %t.readelf-pheaders.txt
 # RUN: cmp %t.readelf-l.txt %t.readelf-pheaders.txt
@@ -12,7 +12,7 @@
 # RUN: llvm-readelf -l %t32.elf | \
 # RUN:   FileCheck %s --check-prefixes=ELF32,MAPPING --strict-whitespace --match-full-lines
 
-# RUN: yaml2obj -DBITS=64 -DMACHINE=EM_X86_64 %s -o %t64.elf
+# RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_X86_64 %s -o %t64.elf
 # RUN: llvm-readelf -l %t64.elf | \
 # RUN:   FileCheck %s --check-prefixes=ELF64,MAPPING --strict-whitespace --match-full-lines
 
@@ -288,7 +288,7 @@ ProgramHeaders:
       - Section: .foo.end
 
 ## Check how we dump ARM specific program headers.
-# RUN: yaml2obj -DBITS=64 -DMACHINE=EM_ARM %s -o %tarm.elf
+# RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_ARM %s -o %tarm.elf
 # RUN: llvm-readelf --program-headers %tarm.elf | FileCheck %s --check-prefix=ARM
 
 # ARM:      <unknown>: 0x70000000 0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
@@ -296,10 +296,61 @@ ProgramHeaders:
 # ARM-NEXT: <unknown>: 0x70000002 0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
 
 ## Check how we dump MIPS specific program headers.
-# RUN: yaml2obj -DBITS=64 -DMACHINE=EM_MIPS %s -o %tmips.elf
+# RUN: yaml2obj --docnum=1 -DBITS=64 -DMACHINE=EM_MIPS %s -o %tmips.elf
 # RUN: llvm-readelf --program-headers %tmips.elf | FileCheck %s --check-prefix=MIPS
 
 # MIPS:      REGINFO  0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
 # MIPS-NEXT: RTPROC   0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
 # MIPS-NEXT: OPTIONS  0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
 # MIPS-NEXT: ABIFLAGS 0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1
+
+## Check we report a warning when a program interpreter name is non-null-terminated or when
+## PT_INTERP has an offset that goes past the end of the file.
+# RUN: yaml2obj --docnum=2 %s -o %t.err
+
+## Show the size of the output produced. It is used in the YAML below.
+# RUN: wc -c < %t.err | FileCheck %s --check-prefix=SIZE
+# SIZE: 560
+
+## Write the additional 'C', '\0, 'C' bytes to the end.
+# RUN: echo -n -e "C\x00C" >> %t.err
+
+# RUN: llvm-readelf --program-headers %t.err 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.err --check-prefix=ERROR-INTERP
+
+# ERROR-INTERP:      Type           Offset
+# ERROR-INTERP-NEXT: INTERP         0x000[[#%x,OFFSET:0x230]]
+# ERROR-INTERP-NEXT:     [Requesting program interpreter: C]
+# ERROR-INTERP-NEXT: INTERP         0x000[[#OFFSET + 1]]
+# ERROR-INTERP-NEXT:     [Requesting program interpreter: ]
+# ERROR-INTERP-NEXT: INTERP         0x000[[#OFFSET + 2]]
+# ERROR-INTERP-NEXT: warning: '[[FILE]]': unable to read program interpreter name at offset 0x[[#OFFSET+2]]: it is not null-terminated
+# ERROR-INTERP-NEXT: INTERP         0x000[[#OFFSET + 3]]
+# ERROR-INTERP-NEXT: warning: '[[FILE]]': unable to read program interpreter name at offset 0x[[#OFFSET+3]]: it goes past the end of the file (0x[[#OFFSET + 3]])
+# ERROR-INTERP-NEXT: INTERP         0xaabbccddeeff1122
+# ERROR-INTERP-NEXT: warning: '[[FILE]]': unable to read program interpreter name at offset 0xaabbccddeeff1122: it goes past the end of the file (0x[[#OFFSET + 3]])
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+ProgramHeaders:
+## Case 1: the offset points to the first additional byte.
+  - Type:   PT_INTERP
+    Offset: 560
+## Case 1: the offset points to the second additional byte,
+##         which is a null byte.
+  - Type:   PT_INTERP
+    Offset: 561
+## Case 3: the offset points to the third additional
+##         byte, which is the last byte in the file.
+  - Type:   PT_INTERP
+    Offset: 562
+## Case 4: the offset goes 1 byte past the end of the file.
+  - Type:   PT_INTERP
+    Offset: 563
+## Case 5: an arbitrary large offset that goes past the end of the file.
+  - Type:   PT_INTERP
+    Offset: 0xAABBCCDDEEFF1122

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 9930c03c6d97..d5513c7f8f13 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4128,8 +4128,31 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
     for (auto Field : Fields)
       printField(Field);
     if (Phdr.p_type == ELF::PT_INTERP) {
-      OS << "\n      [Requesting program interpreter: ";
-      OS << reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset << "]";
+      OS << "\n";
+      auto ReportBadInterp = [&](const Twine &Msg) {
+        reportWarning(
+            createError("unable to read program interpreter name at offset 0x" +
+                        Twine::utohexstr(Phdr.p_offset) + ": " + Msg),
+            this->FileName);
+      };
+
+      if (Phdr.p_offset >= Obj->getBufSize()) {
+        ReportBadInterp("it goes past the end of the file (0x" +
+                        Twine::utohexstr(Obj->getBufSize()) + ")");
+        continue;
+      }
+
+      const char *Data =
+          reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset;
+      size_t MaxSize = Obj->getBufSize() - Phdr.p_offset;
+      size_t Len = strnlen(Data, MaxSize);
+      if (Len == MaxSize) {
+        ReportBadInterp("it is not null-terminated");
+        continue;
+      }
+
+      OS << "      [Requesting program interpreter: ";
+      OS << StringRef(Data, Len) << "]";
     }
     OS << "\n";
   }


        


More information about the llvm-commits mailing list