Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -301,6 +301,8 @@ void addSection(EHInputSection *S); private: + uintX_t readEntryLength(ArrayRef D); + std::vector *> Sections; std::vector> Cies; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/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,32 @@ } 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 Len = read32(D.data()); + if (Len < UINT32_MAX) { + if (Len > (UINT32_MAX - 4)) + error("CIE/FIE size is too large"); + if (Len + 4 > D.size()) + error("CIE/FIE ends past the end of the section"); + return Len + 4; + } + + if (D.size() < 12) + error("Truncated CIE/FDE length"); + Len = read64(D.data() + 4); + if (Len > (UINT64_MAX - 12)) + error("CIE/FIE size is too large"); + if (Len + 12 > D.size()) + error("CIE/FIE ends past the end of the section"); + return Len + 12; +} + +template void EHOutputSection::addSection(EHInputSection *S) { const Elf_Shdr *RelSec = S->RelocSection; if (!RelSec) Index: lld/trunk/test/ELF/invalid-cie-length3.s =================================================================== --- lld/trunk/test/ELF/invalid-cie-length3.s +++ lld/trunk/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: lld/trunk/test/ELF/invalid-cie-length4.s =================================================================== --- lld/trunk/test/ELF/invalid-cie-length4.s +++ lld/trunk/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: lld/trunk/test/ELF/invalid-cie-length5.s =================================================================== --- lld/trunk/test/ELF/invalid-cie-length5.s +++ lld/trunk/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 0xFFFFFFFFFFFFFFF4 + +// CHECK: CIE/FIE size is too large Index: lld/trunk/test/ELF/valid-cie-length-dw64.s =================================================================== --- lld/trunk/test/ELF/valid-cie-length-dw64.s +++ lld/trunk/test/ELF/valid-cie-length-dw64.s @@ -0,0 +1,13 @@ +// 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 1 + nop + +// CHECK-NOT: Truncated CIE/FDE length +// CHECK-NOT: CIE/FIE size is too large +// CHECK-NOT: CIE/FIE ends past the end of the section