Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -301,6 +301,8 @@ void addSection(EHInputSection *S); private: + uintX_t readEntryLength(ArrayRef &D); + std::vector *> Sections; std::vector> Cies; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -943,16 +943,10 @@ DenseMap OffsetToIndex; while (!D.empty()) { - if (D.size() < 4) - error("Truncated CIE/FDE length"); - uint32_t Length = read32(D.data()); - Length += 4; - unsigned Index = S->Offsets.size(); S->Offsets.push_back(std::make_pair(Offset, -1)); - if (Length > D.size()) - error("CIE/FIE ends past the end of the section"); + uintX_t Length = readEntryLength(D); StringRef Entry((const char *)D.data(), Length); while (RelI != RelE && RelI->r_offset < Offset) @@ -999,6 +993,31 @@ } template +typename EHOutputSection::uintX_t +EHOutputSection::readEntryLength(ArrayRef &D) { + const endianness E = ELFT::TargetEndianness; + if (D.size() < 4) + error("Truncated CIE/FDE length"); + uint64_t Length = read32(D.data()); + bool Is64Dwarf = false; + if (Length == (uint32_t)-1) { + // Next 64 bits holds the length, and this is a 64-bit DWARF format + if (D.size() < 12) + error("Truncated CIE/FDE length"); + Length = read64(D.data() + 4); + Is64Dwarf = true; + } + uint32_t Off = Is64Dwarf ? 12 : 4; + // Max = max(int64) - Off or max(int32) - Off + uint64_t Max = Is64Dwarf ? 0xFFFFFFFFFFFFFFED : 0x00000000FFFFFFFB; + if (Length > Max) + error("CIE/FIE size is too large"); + if (Length + Off > D.size()) + error("CIE/FIE ends past the end of the section"); + return (uintX_t)(Length + Off); +} + +template void EHOutputSection::addSection(EHInputSection *S) { const Elf_Shdr *RelSec = S->RelocSection; if (!RelSec) Index: test/ELF/invalid-cie-length3.s =================================================================== --- test/ELF/invalid-cie-length3.s +++ test/ELF/invalid-cie-length3.s @@ -0,0 +1,9 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s + + .section .eh_frame + .long 0xFFFFFFFC + +// CHECK: CIE/FIE size is too large Index: test/ELF/invalid-cie-length4.s =================================================================== --- test/ELF/invalid-cie-length4.s +++ test/ELF/invalid-cie-length4.s @@ -0,0 +1,10 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s + + .section .eh_frame + .long 0xFFFFFFFF + .byte 0 + +// CHECK: Truncated CIE/FDE length Index: test/ELF/invalid-cie-length5.s =================================================================== --- test/ELF/invalid-cie-length5.s +++ test/ELF/invalid-cie-length5.s @@ -0,0 +1,10 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s + + .section .eh_frame + .long 0xFFFFFFFF + .quad 0xFFFFFFFFFFFFFFEE + +// CHECK: CIE/FIE size is too large