diff options
author | Georgii Rymar <grimar@accesssoftek.com> | 2020-07-02 13:38:42 +0300 |
---|---|---|
committer | Georgii Rymar <grimar@accesssoftek.com> | 2020-07-07 11:59:00 +0300 |
commit | d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc (patch) | |
tree | 632f0d83a9da5abf451e64f0c4433ae5f11fd98f /llvm | |
parent | cd503166fb74baf91c55f5f959ed9cd016cbd9f7 (diff) | |
download | llvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.zip llvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.tar.gz llvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.tar.bz2 |
[llvm-readobj] - Fix a crash scenario in GNUStyle<ELFT>::printHashSymbols().
We might crash when the dynamic symbols table is empty (or not found)
and --hash-symbols is requested. Both .hash and .gnu.hash logic is affected.
The patch fixes this issue.
Differential revision: https://reviews.llvm.org/D83037
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/test/tools/llvm-readobj/ELF/hash-symbols.test | 128 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 26 |
2 files changed, 151 insertions, 3 deletions
diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test index b43f3eb..2576fe0 100644 --- a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test +++ b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test @@ -509,3 +509,131 @@ ProgramHeaders: Sections: - Section: .gnu.hash - Section: .dynamic + +## Check the behavior when the dynamic symbol table is empty or not found. + +## Case A.1: Check we report a warning when the dynamic symbol table is empty and we attempt to print hash symbols +## from the .hash table. The number of symbols in the dynamic symbol table can be calculated from its size +## or derived from the Chain vector of the .hash table. Make both ways to return a zero to do the check. +# RUN: yaml2obj --docnum=9 %s -o %t9.1.so +# RUN: llvm-readelf --hash-symbols %t9.1.so 2>&1 | FileCheck %s -DFILE=%t9.1.so --check-prefix=DYNSYM-EMPTY-HASH + +# DYNSYM-EMPTY-HASH: Symbol table of .hash for image: +# DYNSYM-EMPTY-HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-EMPTY-HASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .hash table: the dynamic symbol table is empty +# DYNSYM-EMPTY-HASH-NOT: {{.}} + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Bucket: [ 0 ] + Chain: [ ] + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Entries: + - Tag: DT_HASH + Value: 0x0 + - Tag: DT_STRTAB +## PT_LOAD p_offset == .hash offset == 0x54. +## 0x54 + 0x2c == 0x80 == .dynstr offset. + Value: 0x2c + - Tag: DT_STRSZ + Value: 0x1 + - Tag: DT_NULL + Value: 0x0 + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + - Name: .dynsym + Type: [[DYNSYMTYPE=SHT_DYNSYM]] + Flags: [ SHF_ALLOC ] + Size: 0 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + Sections: + - Section: .hash + - Section: .dynamic + - Section: .dynstr + +## Case A.2: similar to A.1, but now check that we report a warning when the dynamic symbol table was not found. +## To do that, set the type of the .dynsym to SHT_PROGBITS to hide it. +# RUN: yaml2obj --docnum=9 -DDYNSYMTYPE=SHT_PROGBITS %s -o %t9.2.so +# RUN: llvm-readelf --hash-symbols %t9.2.so 2>&1 | FileCheck %s -DFILE=%t9.2.so --check-prefix=DYNSYM-NOTFOUND-HASH + +# DYNSYM-NOTFOUND-HASH: Symbol table of .hash for image: +# DYNSYM-NOTFOUND-HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-NOTFOUND-HASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .hash table: the dynamic symbol table was not found +# DYNSYM-NOTFOUND-HASH-NOT: {{.}} + +## Case B.1: Check we report a warning when the dynamic symbol table is empty and we attempt to print +## hash symbols from the .gnu.hash table. +# RUN: yaml2obj --docnum=10 %s -o %t10.1.so +# RUN: llvm-readelf --hash-symbols %t10.1.so 2>&1 | FileCheck %s -DFILE=%t10.1.so --check-prefix=DYNSYM-EMPTY-GNUHASH + +# DYNSYM-EMPTY-GNUHASH: Symbol table of .gnu.hash for image: +# DYNSYM-EMPTY-GNUHASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-EMPTY-GNUHASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .gnu.hash table: the dynamic symbol table is empty +# DYNSYM-EMPTY-GNUHASH-NOT: {{.}} + +## Case B.2: similar to B.1, but now check that we report a warning when the dynamic symbol table was not found. +## To do that, set the type of the .dynsym to SHT_PROGBITS to hide it. +# RUN: yaml2obj --docnum=10 -DDYNSYMTYPE=SHT_PROGBITS %s -o %t10.2.so +# RUN: llvm-readelf --hash-symbols %t10.2.so 2>&1 | FileCheck %s -DFILE=%t10.2.so --check-prefix=DYNSYM-NOTFOUND-GNUHASH + +# DYNSYM-NOTFOUND-GNUHASH: Symbol table of .gnu.hash for image: +# DYNSYM-NOTFOUND-GNUHASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# DYNSYM-NOTFOUND-GNUHASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .gnu.hash table: the dynamic symbol table was not found +# DYNSYM-NOTFOUND-GNUHASH-NOT: {{.}} + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .gnu.hash + Type: SHT_GNU_HASH + Flags: [ SHF_ALLOC ] + Header: + SymNdx: 0x0 + Shift2: 0x0 + BloomFilter: [ 0x0 ] + HashBuckets: [ 0x1 ] + HashValues: [ 0x0 ] + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Entries: + - Tag: DT_GNU_HASH + Value: 0x0 + - Tag: DT_STRTAB +## PT_LOAD p_offset == .hash offset == 0x54. +## 0x54 + 0x3c == 0x80 == .dynstr offset. + Value: 0x3c + - Tag: DT_STRSZ + Value: 0x1 + - Tag: DT_NULL + Value: 0x0 + - Name: .dynstr + Type: SHT_STRTAB + - Name: .dynsym + Type: [[DYNSYMTYPE=SHT_DYNSYM]] + Flags: [ SHF_ALLOC ] + Size: 0 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + Sections: + - Section: .gnu.hash + - Section: .dynamic + - Section: .dynstr diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index e2ea2c3..7a29606 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4066,7 +4066,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { if (this->dumper()->getDynamicStringTable().empty()) return; auto StringTable = this->dumper()->getDynamicStringTable(); - auto DynSyms = this->dumper()->dynamic_symbols(); + Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols(); auto PrintHashTable = [&](const Elf_Hash *SysVHash) { if (ELFT::Is64Bits) @@ -4075,6 +4075,16 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; + const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; + if (!FirstSym) { + Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion(); + this->reportUniqueWarning( + createError(Twine("unable to print symbols for the .hash table: the " + "dynamic symbol table ") + + (DynSymRegion ? "is empty" : "was not found"))); + return; + } + auto Buckets = SysVHash->buckets(); auto Chains = SysVHash->chains(); for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) { @@ -4093,7 +4103,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { break; } - printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc); + printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc); Visited[Ch] = true; } } @@ -4124,6 +4134,16 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { return; } + const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; + if (!FirstSym) { + Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion(); + this->reportUniqueWarning(createError( + Twine("unable to print symbols for the .gnu.hash table: the " + "dynamic symbol table ") + + (DynSymRegion ? "is empty" : "was not found"))); + return; + } + auto Buckets = GnuHash->buckets(); for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) @@ -4132,7 +4152,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { uint32_t GnuHashable = Index - GnuHash->symndx; // Print whole chain while (true) { - printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc); + printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc); // Chain ends at symbol with stopper bit if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1) break; |