Index: llvm/test/tools/llvm-readobj/ELF/hash-histogram.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/hash-histogram.test +++ llvm/test/tools/llvm-readobj/ELF/hash-histogram.test @@ -268,3 +268,53 @@ - Section: .hash - Section: .gnu.hash - Section: .dynamic + +## Check we report a proper warning when the GNU hash table goes past the end of the file. + +## Case A: the 'nbuckets' field is set so that the GNU hash table goes past the end of the file. +# RUN: yaml2obj --docnum=6 -D MASKWORDS=4294967295 -D NBUCKETS=3 %s -o %t7 +# RUN: llvm-readelf --elf-hash-histogram %t7 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t7 -DMASKWORDS=4294967295 -DNBUCKETS=3 --check-prefix=ERR5 + +# ERR5: warning: '[[FILE]]': unable to dump the SHT_GNU_HASH section at 0x78: it goes past the end of the file + +## Case B: the 'maskwords' field is set so that the GNU hash table goes past the end of the file. +# RUN: yaml2obj --docnum=6 -D MASKWORDS=2 -D NBUCKETS=4294967295 %s -o %t8 +# RUN: llvm-readelf --elf-hash-histogram %t8 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t8 -DMASKWORDS=2 -DNBUCKETS=4294967295 --check-prefix=ERR5 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .gnu.hash + Type: SHT_GNU_HASH + Flags: [ SHF_ALLOC ] + Header: + SymNdx: 0x0 + Shift2: 0x0 +## The number of words in the Bloom filter. The value of 2 is no-op. + MaskWords: [[MASKWORDS]] +## The number of hash buckets. The value of 3 is no-op. + NBuckets: [[NBUCKETS]] + BloomFilter: [ 0x0 ] + HashBuckets: [ 0x0 ] + HashValues: [ 0x0 ] + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Link: .dynstr + Entries: + - Tag: DT_GNU_HASH + Value: 0x0 + - Tag: DT_NULL + Value: 0x0 +DynamicSymbols: [] +ProgramHeaders: + - Type: PT_LOAD + Sections: + - Section: .gnu.hash + - Section: .dynamic Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2660,6 +2660,30 @@ return true; } +template +static bool checkGNUHashTable(const ELFFile *Obj, + const typename ELFT::GnuHash *GnuHashTable, + StringRef FileName) { + const uint8_t *TableData = reinterpret_cast(GnuHashTable); + assert(TableData >= Obj->base() && + TableData < Obj->base() + Obj->getBufSize() && + "GnuHashTable must always point to a location inside the file"); + + uint64_t TableOffset = TableData - Obj->base(); + if (TableOffset + + /*Header size:*/ 16 + GnuHashTable->nbuckets * 4 + + GnuHashTable->maskwords * sizeof(typename ELFT::Off) >= + Obj->getBufSize()) { + reportWarning(createError("unable to dump the SHT_GNU_HASH " + "section at 0x" + + Twine::utohexstr(TableOffset) + + ": it goes past the end of the file"), + FileName); + return false; + } + return true; +} + template void ELFDumper::printHashTable() { DictScope D(W, "HashTable"); if (!HashTable || @@ -2681,24 +2705,9 @@ W.printNumber("Num Mask Words", GnuHashTable->maskwords); W.printNumber("Shift Count", GnuHashTable->shift2); - MemoryBufferRef File = Obj->getMemoryBufferRef(); - const char *TableData = reinterpret_cast(GnuHashTable); - assert(TableData >= File.getBufferStart() && - TableData < File.getBufferEnd() && - "GnuHashTable must always point to a location inside the file"); - - uint64_t TableOffset = TableData - File.getBufferStart(); - if (TableOffset + - /*Header size:*/ 16 + GnuHashTable->nbuckets * 4 + - GnuHashTable->maskwords * sizeof(typename ELFT::Off) >= - File.getBufferSize()) { - reportWarning(createError("unable to dump the SHT_GNU_HASH " - "section at 0x" + - Twine::utohexstr(TableOffset) + - ": it goes past the end of the file"), - ObjF->getFileName()); + if (!checkGNUHashTable(ObjF->getELFFile(), GnuHashTable, + ObjF->getFileName())) return; - } ArrayRef BloomFilter = GnuHashTable->filter(); W.printHexList("Bloom Filter", BloomFilter); @@ -4673,7 +4682,8 @@ // Print histogram for the .gnu.hash section. if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) - PrintGnuHashHist(*GnuHashTable); + if (checkGNUHashTable(Obj, GnuHashTable, this->FileName)) + PrintGnuHashHist(*GnuHashTable); } template