diff --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test --- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test +++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols-size-from-hash-table.test @@ -324,3 +324,94 @@ # LLVM3: DynamicSymbols [ # LLVM3: ] + +## Case 4: The size of the dynamic symbol table, inferred from the hash table, is broken. +## It is so large that symbol table goes past the end of the file. We have a dynamic +## relocation which refers to a symbol with an index that is also too large to be +## in the file. Check we report a warning when trying to dump this relocation. + +# RUN: yaml2obj --docnum=3 %s -o %t4.1 + +## Remember the size of the output produced. +# RUN: wc -c %t4.1 > %t4.out.gnu.txt +# RUN: llvm-readelf --sections --dyn-relocations %t4.1 >> %t4.out.gnu.txt 2>&1 +# RUN: FileCheck %s -DFILE=%t4.1 --input-file=%t4.out.gnu.txt --check-prefix=BROKEN-NCHAIN-GNU + +# BROKEN-NCHAIN-GNU: [[#%u, FILESIZE:]] +# BROKEN-NCHAIN-GNU: warning: '[[FILE]]': the size (0x17ffffffe8) of the dynamic symbol table at 0x[[#%x, DYNSYMOFF:]], derived from the hash table, goes past the end of the file (0x[[#%x, FILESIZE]]) and will be ignored + +# BROKEN-NCHAIN-GNU: [Nr] Name Type Address Off +# BROKEN-NCHAIN-GNU: [ 1] .rela.plt RELA 0000000000001000 0000[[#%x, RELAOFF:]] +# BROKEN-NCHAIN-GNU: [ 4] .dynsym DYNSYM 0000000000001078 0000[[#%x, DYNSYMOFF]] + +# BROKEN-NCHAIN-GNU: 'PLT' relocation section at offset 0x[[#%x, RELAOFF]] contains 24 bytes: +# BROKEN-NCHAIN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# BROKEN-NCHAIN-GNU-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4292739037: index is greater than or equal to the number of dynamic symbols (1) +# BROKEN-NCHAIN-GNU-NEXT: 0000000000000000 ffddffdd00000000 R_X86_64_NONE + 0 + +# RUN: wc -c %t4.1 > %t4.out.llvm.txt +# RUN: llvm-readobj --sections --dyn-relocations %t4.1 2>&1 >> %t4.out.llvm.txt 2>&1 +# RUN: FileCheck %s -DFILE=%t4.1 --input-file=%t4.out.llvm.txt --check-prefix=BROKEN-NCHAIN-LLVM + +# BROKEN-NCHAIN-LLVM: {{^}}[[#%u, FILESIZE:]] +# BROKEN-NCHAIN-LLVM: warning: '[[FILE]]': the size (0x17ffffffe8) of the dynamic symbol table at 0x[[#%x, DYNSYMOFF:]], derived from the hash table, goes past the end of the file (0x[[#%x, FILESIZE]]) and will be ignored + +# BROKEN-NCHAIN-LLVM: Name: .dynsym +# BROKEN-NCHAIN-LLVM-NEXT: Type: SHT_DYNSYM +# BROKEN-NCHAIN-LLVM-NEXT: Flags [ +# BROKEN-NCHAIN-LLVM-NEXT: SHF_ALLOC +# BROKEN-NCHAIN-LLVM-NEXT: ] +# BROKEN-NCHAIN-LLVM-NEXT: Address: 0x1078 +# BROKEN-NCHAIN-LLVM-NEXT: Offset: 0x[[#%X, DYNSYMOFF]] + +# BROKEN-NCHAIN-LLVM: Dynamic Relocations { +# BROKEN-NCHAIN-LLVM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4292739037: index is greater than or equal to the number of dynamic symbols (1) +# BROKEN-NCHAIN-LLVM-NEXT: 0x0 R_X86_64_NONE 0x0 +# BROKEN-NCHAIN-LLVM-NEXT: } + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .rela.plt + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Relocations: + - Type: R_X86_64_NONE + Symbol: 0xFFDDFFDD + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Entries: + - Tag: DT_PLTRELSZ + Value: 0x18 + - Tag: DT_JMPREL +## 0x1000 - PT_LOAD's p_vaddr (0x1000) == 0x0. +## 0x0 + PT_LOAD's p_offset (0x78) == .rela.plt section offset (0x78). + Value: 0x1000 + - Tag: DT_PLTREL + Value: 0x7 ## 7 == DT_RELA + - Tag: DT_HASH +## 0x1068 - PT_LOAD's p_vaddr (0x1000) == 0x68. +## 0x68 + PT_LOAD's p_offset (0x78) == .hash section offset (0xE0). + Value: 0x1068 + - Tag: DT_NULL + Value: 0x0 + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Bucket: [ 0 ] + Chain: [ 0 ] + NChain: 0xFFFFFFFF +DynamicSymbols: [] +ProgramHeaders: + - Type: PT_LOAD + Sections: + - Section: .rela.plt + - Section: .dynamic + - Section: .hash + VAddr: 0x1000 diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test --- a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test +++ b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test @@ -167,6 +167,7 @@ # RUN: llvm-readelf --elf-hash-histogram %t4.3.o 2>&1 | \ # RUN: FileCheck %s --check-prefix=ERR3 -DFILE=%t4.3.o --implicit-check-not="warning:" # ERR3: warning: '[[FILE]]': hash table nchain (93) differs from symbol count derived from SHT_DYNSYM section header (1){{$}} +# ERR3: warning: '[[FILE]]': the size (0x5d0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored ## Case B.2: the hash table ends 1 byte past the EOF. We have a broken nchain ## field that has a value larger than the number of chains. @@ -174,6 +175,7 @@ # RUN: llvm-readelf --elf-hash-histogram %t4.4.o 2>&1 | \ # RUN: FileCheck %s --check-prefix=ERR4 -DFILE=%t4.4.o --implicit-check-not="warning:" # ERR4: warning: '[[FILE]]': hash table nchain (94) differs from symbol count derived from SHT_DYNSYM section header (1){{$}} +# ERR4: warning: '[[FILE]]': the size (0x5e0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored # ERR4: warning: '[[FILE]]': the hash table at offset 0x54 goes past the end of the file (0x1d4), nbucket = 1, nchain = 94{{$}} --- !ELF diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test --- a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test +++ b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test @@ -402,6 +402,7 @@ # RUN: llvm-readelf --hash-symbols %t7.3.o 2>&1 | \ # RUN: FileCheck %s --implicit-check-not="warning:" --check-prefix=NOERR2 -DFILE=%t7.3.o # NOERR2: warning: '[[FILE]]': hash table nchain (93) differs from symbol count derived from SHT_DYNSYM section header (1) +# NOERR2: warning: '[[FILE]]': the size (0x5d0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored # NOERR2: Symbol table of .hash for image: # NOERR2-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name # NOERR2-NOT: {{.}} diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-table.test b/llvm/test/tools/llvm-readobj/ELF/hash-table.test --- a/llvm/test/tools/llvm-readobj/ELF/hash-table.test +++ b/llvm/test/tools/llvm-readobj/ELF/hash-table.test @@ -169,6 +169,7 @@ # RUN: FileCheck %s --check-prefix=NOERR2 -DFILE=%t5.3.o --implicit-check-not="warning:" # NOERR2: warning: '[[FILE]]': hash table nchain (93) differs from symbol count derived from SHT_DYNSYM section header (1) +# NOERR2: warning: '[[FILE]]': the size (0x5d0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored # NOERR2: HashTable { # NOERR2-NEXT: Num Buckets: 1 # NOERR2-NEXT: Num Chains: 93 @@ -187,6 +188,7 @@ # RUN: FileCheck %s --check-prefix=ERR3 -DFILE=%t5.4.o --implicit-check-not="warning:" # ERR3: warning: '[[FILE]]': hash table nchain (94) differs from symbol count derived from SHT_DYNSYM section header (1) +# ERR3: warning: '[[FILE]]': the size (0x5e0) of the dynamic symbol table at 0x78, derived from the hash table, goes past the end of the file (0x1d4) and will be ignored # ERR3: HashTable { # ERR3-NEXT: Num Buckets: 1 # ERR3-NEXT: Num Chains: 94 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2250,8 +2250,21 @@ // Derive the dynamic symbol table size from the DT_HASH hash table, if // present. - if (HashTable && DynSymRegion) - DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize; + if (HashTable && DynSymRegion) { + const uint64_t FileSize = ObjF->getELFFile()->getBufSize(); + const uint64_t DerivedSize = + (uint64_t)HashTable->nchain * DynSymRegion->EntSize; + const uint64_t Offset = + (const uint8_t *)DynSymRegion->Addr - ObjF->getELFFile()->base(); + if (DerivedSize > FileSize - Offset) + reportUniqueWarning(createError( + "the size (0x" + Twine::utohexstr(DerivedSize) + + ") of the dynamic symbol table at 0x" + Twine::utohexstr(Offset) + + ", derived from the hash table, goes past the end of the file (0x" + + Twine::utohexstr(FileSize) + ") and will be ignored")); + else + DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize; + } } template