diff options
-rw-r--r-- | lld/ELF/OutputSections.cpp | 34 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | lld/test/ELF/invalid-cie-length3.s | 9 | ||||
-rw-r--r-- | lld/test/ELF/invalid-cie-length4.s | 10 | ||||
-rw-r--r-- | lld/test/ELF/invalid-cie-length5.s | 10 | ||||
-rw-r--r-- | lld/test/ELF/valid-cie-length-dw64.s | 13 |
6 files changed, 71 insertions, 7 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 723da267e6f..50f48022940 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -943,16 +943,10 @@ void EHOutputSection<ELFT>::addSectionAux( DenseMap<unsigned, unsigned> OffsetToIndex; while (!D.empty()) { - if (D.size() < 4) - error("Truncated CIE/FDE length"); - uint32_t Length = read32<E>(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 @@ void EHOutputSection<ELFT>::addSectionAux( } template <class ELFT> +typename EHOutputSection<ELFT>::uintX_t +EHOutputSection<ELFT>::readEntryLength(ArrayRef<uint8_t> D) { + const endianness E = ELFT::TargetEndianness; + + if (D.size() < 4) + error("Truncated CIE/FDE length"); + uint64_t Len = read32<E>(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<E>(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 <class ELFT> void EHOutputSection<ELFT>::addSection(EHInputSection<ELFT> *S) { const Elf_Shdr *RelSec = S->RelocSection; if (!RelSec) diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 2332308a578..0626b9ddea0 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -301,6 +301,8 @@ public: void addSection(EHInputSection<ELFT> *S); private: + uintX_t readEntryLength(ArrayRef<uint8_t> D); + std::vector<EHInputSection<ELFT> *> Sections; std::vector<Cie<ELFT>> Cies; diff --git a/lld/test/ELF/invalid-cie-length3.s b/lld/test/ELF/invalid-cie-length3.s new file mode 100644 index 00000000000..8f3ab1cf29d --- /dev/null +++ b/lld/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 diff --git a/lld/test/ELF/invalid-cie-length4.s b/lld/test/ELF/invalid-cie-length4.s new file mode 100644 index 00000000000..4a51ca1f812 --- /dev/null +++ b/lld/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 diff --git a/lld/test/ELF/invalid-cie-length5.s b/lld/test/ELF/invalid-cie-length5.s new file mode 100644 index 00000000000..14054a2dee8 --- /dev/null +++ b/lld/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 diff --git a/lld/test/ELF/valid-cie-length-dw64.s b/lld/test/ELF/valid-cie-length-dw64.s new file mode 100644 index 00000000000..65d6952448a --- /dev/null +++ b/lld/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 |