Index: llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test =================================================================== --- llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test +++ llvm/test/tools/llvm-readobj/ELF/broken-dynamic-reloc.test @@ -319,3 +319,89 @@ - Section: .rela.dyn - Section: .rel.dyn - Section: .dynamic + +## Check that llvm-readobj/llvm-readelf reports a warning when dumping a relocation +## which refers to a symbol past the end of the file. + +# RUN: yaml2obj --docnum=7 %s -o %t7 +# RUN: llvm-readobj -a --dyn-relocations %t7 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t7 --check-prefix=PAST-EOF-LLVM +# RUN: llvm-readelf -a --dyn-relocations %t7 2>&1 | \ +# RUN: FileCheck %s -DFILE=%t7 --check-prefix=PAST-EOF-GNU + +# PAST-EOF-LLVM: Dynamic Relocations { +# PAST-EOF-LLVM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 20: st_name (0x0) is past the end of the string table of size 0x0 +# PAST-EOF-LLVM-NEXT: 0x0 R_X86_64_NONE 0x0 +# PAST-EOF-LLVM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 21: symbol at 0x4f8 goes past the end of the file (0x4f8) +# PAST-EOF-LLVM-NEXT: 0x0 R_X86_64_NONE 0x0 +# PAST-EOF-LLVM-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4294967295: symbol at 0x18000002e8 goes past the end of the file (0x4f8) +# PAST-EOF-LLVM-NEXT: 0x0 R_X86_64_NONE 0x0 +# PAST-EOF-LLVM-NEXT: } + +# PAST-EOF-GNU: 'RELA' relocation section at offset 0x200 contains 72 bytes: +# PAST-EOF-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# PAST-EOF-GNU-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 20: st_name (0x0) is past the end of the string table of size 0x0 +# PAST-EOF-GNU-NEXT: 0000000000000000 0000001400000000 R_X86_64_NONE 0000000000000001 + 0 +# PAST-EOF-GNU-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 21: symbol at 0x4f8 goes past the end of the file (0x4f8) +# PAST-EOF-GNU-NEXT: 0000000000000000 0000001500000000 R_X86_64_NONE + 0 +# PAST-EOF-GNU-NEXT: warning: '[[FILE]]': unable to get name of the dynamic symbol with index 4294967295: symbol at 0x18000002e8 goes past the end of the file (0x4f8) +# PAST-EOF-GNU-NEXT: 0000000000000000 ffffffff00000000 R_X86_64_NONE + 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x100 + Offset: 0x100 + Entries: + - Tag: DT_RELA + Value: 0x200 + - Tag: DT_SYMTAB + Value: 0x300 + - Tag: DT_RELASZ + Value: 0x48 + - Tag: DT_RELAENT + Value: 0x18 + - Tag: DT_NULL + Value: 0x0 + - Name: .rela.dyn + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + Address: 0x200 + Offset: 0x200 + Relocations: +## This symbol is located right before the EOF, so we can dump it. + - Symbol: 0x14 + Type: R_X86_64_NONE +## The next symbol, which goes past the EOF. + - Symbol: 0x15 + Type: R_X86_64_NONE +## One more symbol that goes past the EOF +## with the maximal possible index. + - Symbol: 0xFFFFFFFF + Type: R_X86_64_NONE + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x300 + Offset: 0x300 +DynamicSymbols: + - Name: foo +ProgramHeaders: + - Type: PT_LOAD + Offset: 0x0 + Sections: + - Section: .dynamic + - Section: .rela.dyn + - Section: .dynsym + - Type: PT_DYNAMIC + Sections: + - Section: .dynamic +SectionHeaderTable: + NoHeaders: true Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -4493,7 +4493,8 @@ RelSymbol getSymbolForReloc(const ELFFile &Obj, StringRef FileName, const ELFDumper &Dumper, const Relocation &Reloc) { - auto WarnAndReturn = [&](const typename ELFT::Sym *Sym, + using Elf_Sym = typename ELFT::Sym; + auto WarnAndReturn = [&](const Elf_Sym *Sym, const Twine &Reason) -> RelSymbol { reportWarning( createError("unable to get name of the dynamic symbol with index " + @@ -4502,8 +4503,8 @@ return {Sym, ""}; }; - ArrayRef Symbols = Dumper.dynamic_symbols(); - const typename ELFT::Sym *FirstSym = Symbols.begin(); + ArrayRef Symbols = Dumper.dynamic_symbols(); + const Elf_Sym *FirstSym = Symbols.begin(); if (!FirstSym) return WarnAndReturn(nullptr, "no dynamic symbol table found"); @@ -4516,7 +4517,15 @@ "index is greater than or equal to the number of dynamic symbols (" + Twine(Symbols.size()) + ")"); - const typename ELFT::Sym *Sym = FirstSym + Reloc.Symbol; + const uint64_t FileSize = Obj.getBufSize(); + const uint64_t SymOffset = ((const uint8_t *)FirstSym - Obj.base()) + + (uint64_t)Reloc.Symbol * sizeof(Elf_Sym); + if (SymOffset + sizeof(Elf_Sym) > FileSize) + return WarnAndReturn(nullptr, "symbol at 0x" + Twine::utohexstr(SymOffset) + + " goes past the end of the file (0x" + + Twine::utohexstr(FileSize) + ")"); + + const Elf_Sym *Sym = FirstSym + Reloc.Symbol; Expected ErrOrName = Sym->getName(Dumper.getDynamicStringTable()); if (!ErrOrName) return WarnAndReturn(Sym, toString(ErrOrName.takeError()));