summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/OutputSections.cpp34
-rw-r--r--lld/ELF/OutputSections.h2
-rw-r--r--lld/test/ELF/invalid-cie-length3.s9
-rw-r--r--lld/test/ELF/invalid-cie-length4.s10
-rw-r--r--lld/test/ELF/invalid-cie-length5.s10
-rw-r--r--lld/test/ELF/valid-cie-length-dw64.s13
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
OpenPOWER on IntegriCloud