From 0d54612164519c874eecf5a1be68597b96410628 Mon Sep 17 00:00:00 2001 From: Georgii Rymar Date: Tue, 28 Apr 2020 18:16:00 +0300 Subject: [PATCH] [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 --- llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test | 59 +++++++++++++++++++++++-- llvm/tools/llvm-readobj/ELFDumper.cpp | 27 ++++++++++- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test b/llvm/test/tools/llvm-readobj/ELF/gnu-phdrs.test index 324fa9f..cc3a38f 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: : 0x70000000 0x000548 0x0000000000001000 0x0000000000001000 0x000003 0x000003 0x1 @@ -296,10 +296,61 @@ ProgramHeaders: # ARM-NEXT: : 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 9930c03..d5513c7 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4128,8 +4128,31 @@ void GNUStyle::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(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(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"; } -- 2.7.4