[ELF] - implement support of extended length field for CIE/FDE records of eh_frame.

Ian Lance Taylor writes: "Read 4 bytes. If they are not 0xffffffff, they are the length of the CIE or FDE record. Otherwise the next 64 bits holds the length, and this is a 64-bit DWARF format. This is like .debug_frame." (http://www.airs.com/blog/archives/460), that also consistent with spec (https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html).

Patch implements support of described extended length field and also adds few more checks for safety.

Differential revision: http://reviews.llvm.org/D15532

llvm-svn: 255883
This commit is contained in:
George Rimar
2015-12-17 09:23:40 +00:00
parent a6c8217c25
commit 003be4fd58
6 changed files with 71 additions and 7 deletions

View File

@@ -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)
@@ -998,6 +992,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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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