[lld] r291524 - ELF: Reserve space for copy relocations of read-only symbols in relro.
Peter Collingbourne via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 9 17:21:51 PST 2017
Author: pcc
Date: Mon Jan 9 19:21:50 2017
New Revision: 291524
URL: http://llvm.org/viewvc/llvm-project?rev=291524&view=rev
Log:
ELF: Reserve space for copy relocations of read-only symbols in relro.
When reserving copy relocation space for a shared symbol, scan the DSO's
program headers to see if the symbol is in a read-only segment. If so,
reserve space for that symbol in a new synthetic section named .bss.rel.ro
which will be covered by the relro program header.
This fixes the security issue disclosed on the binutils mailing list at:
https://sourceware.org/ml/libc-alpha/2016-12/msg00914.html
Differential Revision: https://reviews.llvm.org/D28272
Added:
lld/trunk/test/ELF/Inputs/relocation-copy-relro.s
lld/trunk/test/ELF/relocation-copy-relro.s
Modified:
lld/trunk/ELF/OutputSections.h
lld/trunk/ELF/Relocations.cpp
lld/trunk/ELF/Symbols.cpp
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/SyntheticSections.cpp
lld/trunk/ELF/Writer.cpp
lld/trunk/test/ELF/Inputs/copy-rel-pie.s
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Mon Jan 9 19:21:50 2017
@@ -206,6 +206,7 @@ template <class ELFT> struct Out {
static uint8_t First;
static EhOutputSection<ELFT> *EhFrame;
static OutputSection<ELFT> *Bss;
+ static OutputSection<ELFT> *BssRelRo;
static OutputSectionBase *Opd;
static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
@@ -252,6 +253,7 @@ template <class ELFT> uint64_t getHeader
template <class ELFT> uint8_t Out<ELFT>::First;
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
+template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr;
Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Mon Jan 9 19:21:50 2017
@@ -399,7 +399,21 @@ template <class ELFT> static uint32_t ge
return 1 << TrailingZeros;
}
-// Reserve space in .bss for copy relocation.
+template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Phdr Elf_Phdr;
+
+ // Determine if the symbol is read-only by scanning the DSO's program headers.
+ uintX_t Value = SS->Sym.st_value;
+ for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers()))
+ if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
+ !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr &&
+ Value < Phdr.p_vaddr + Phdr.p_memsz)
+ return true;
+ return false;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
@@ -409,10 +423,16 @@ template <class ELFT> static void addCop
if (SymSize == 0)
fatal("cannot create a copy relocation for symbol " + toString(*SS));
+ // See if this symbol is in a read-only segment. If so, preserve the symbol's
+ // memory protection by reserving space in the .bss.rel.ro section.
+ bool IsReadOnly = isReadOnly(SS);
+ OutputSection<ELFT> *CopySec =
+ IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
+
uintX_t Alignment = getAlignment(SS);
- uintX_t Off = alignTo(Out<ELFT>::Bss->Size, Alignment);
- Out<ELFT>::Bss->Size = Off + SymSize;
- Out<ELFT>::Bss->updateAlignment(Alignment);
+ uintX_t Off = alignTo(CopySec->Size, Alignment);
+ CopySec->Size = Off + SymSize;
+ CopySec->updateAlignment(Alignment);
uintX_t Shndx = SS->Sym.st_shndx;
uintX_t Value = SS->Sym.st_value;
// Look through the DSO's dynamic symbol table for aliases and create a
@@ -425,12 +445,12 @@ template <class ELFT> static void addCop
Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
if (!Alias)
continue;
- Alias->OffsetInBss = Off;
+ Alias->CopyIsInBssRelRo = IsReadOnly;
+ Alias->CopyOffset = Off;
Alias->NeedsCopyOrPltAddr = true;
Alias->symbol()->IsUsedInRegularObj = true;
}
- In<ELFT>::RelaDyn->addReloc(
- {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
+ In<ELFT>::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, false, SS, 0});
}
template <class ELFT>
Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Mon Jan 9 19:21:50 2017
@@ -81,7 +81,7 @@ static typename ELFT::uint getSymVA(cons
return 0;
if (SS.isFunc())
return Body.getPltVA<ELFT>();
- return Out<ELFT>::Bss->Addr + SS.OffsetInBss;
+ return SS.getBssSectionForCopy()->Addr + SS.CopyOffset;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -97,7 +97,8 @@ SymbolBody::SymbolBody(Kind K, StringRef
uint8_t Type)
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
+ IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther),
+ Name(Name) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@@ -245,6 +246,12 @@ Undefined<ELFT>::Undefined(StringRefZ Na
this->File = File;
}
+template <typename ELFT>
+OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const {
+ assert(needsCopy());
+ return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
+}
+
DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
: Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
@@ -366,6 +373,11 @@ template class elf::Undefined<ELF32BE>;
template class elf::Undefined<ELF64LE>;
template class elf::Undefined<ELF64BE>;
+template class elf::SharedSymbol<ELF32LE>;
+template class elf::SharedSymbol<ELF32BE>;
+template class elf::SharedSymbol<ELF64LE>;
+template class elf::SharedSymbol<ELF64BE>;
+
template class elf::DefinedRegular<ELF32LE>;
template class elf::DefinedRegular<ELF32BE>;
template class elf::DefinedRegular<ELF64LE>;
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Jan 9 19:21:50 2017
@@ -123,6 +123,11 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
+ // True if this is a shared symbol in a read-only segment which requires a
+ // copy relocation. This causes space for the symbol to be allocated in the
+ // .bss.rel.ro section.
+ unsigned CopyIsInBssRelRo : 1;
+
// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
@@ -282,13 +287,15 @@ public:
// This field is a pointer to the symbol's version definition.
const Elf_Verdef *Verdef;
- // OffsetInBss is significant only when needsCopy() is true.
- uintX_t OffsetInBss = 0;
+ // CopyOffset is significant only when needsCopy() is true.
+ uintX_t CopyOffset = 0;
// If non-null the symbol has a Thunk that may be used as an alternative
// destination for callers of this Symbol.
Thunk<ELFT> *ThunkData = nullptr;
bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
+
+ OutputSection<ELFT> *getBssSectionForCopy() const;
};
// This class represents a symbol defined in an archive file. It is
Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Mon Jan 9 19:21:50 2017
@@ -1201,10 +1201,12 @@ SymbolTableSection<ELFT>::getOutputSecti
}
case SymbolBody::DefinedCommonKind:
return In<ELFT>::Common->OutSec;
- case SymbolBody::SharedKind:
- if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
- return Out<ELFT>::Bss;
+ case SymbolBody::SharedKind: {
+ auto &SS = cast<SharedSymbol<ELFT>>(*Sym);
+ if (SS.needsCopy())
+ return SS.getBssSectionForCopy();
break;
+ }
case SymbolBody::UndefinedKind:
case SymbolBody::LazyArchiveKind:
case SymbolBody::LazyObjectKind:
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Jan 9 19:21:50 2017
@@ -250,6 +250,8 @@ template <class ELFT> void Writer<ELFT>:
// Create singleton output sections.
Out<ELFT>::Bss =
make<OutputSection<ELFT>>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ Out<ELFT>::BssRelRo = make<OutputSection<ELFT>>(".bss.rel.ro", SHT_NOBITS,
+ SHF_ALLOC | SHF_WRITE);
In<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
@@ -498,6 +500,8 @@ template <class ELFT> bool elf::isRelroS
return true;
if (In<ELFT>::MipsGot && Sec == In<ELFT>::MipsGot->OutSec)
return true;
+ if (Sec == Out<ELFT>::BssRelRo)
+ return true;
StringRef S = Sec->getName();
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
S == ".eh_frame" || S == ".openbsd.randomdata";
@@ -1079,6 +1083,8 @@ template <class ELFT> void Writer<ELFT>:
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
if (Out<ELFT>::Bss->Size > 0)
OutputSections.push_back(Out<ELFT>::Bss);
+ if (Out<ELFT>::BssRelRo->Size > 0)
+ OutputSections.push_back(Out<ELFT>::BssRelRo);
auto OS = dyn_cast_or_null<OutputSection<ELFT>>(findSection(".ARM.exidx"));
if (OS && !OS->Sections.empty() && !Config->Relocatable)
Modified: lld/trunk/test/ELF/Inputs/copy-rel-pie.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/copy-rel-pie.s?rev=291524&r1=291523&r2=291524&view=diff
==============================================================================
--- lld/trunk/test/ELF/Inputs/copy-rel-pie.s (original)
+++ lld/trunk/test/ELF/Inputs/copy-rel-pie.s Mon Jan 9 19:21:50 2017
@@ -1,9 +1,11 @@
+.data
.global foo
.type foo, @object
.size foo, 4
foo:
.long 0
+.text
.global bar
.type bar, @function
bar:
Added: lld/trunk/test/ELF/Inputs/relocation-copy-relro.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/relocation-copy-relro.s?rev=291524&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/relocation-copy-relro.s (added)
+++ lld/trunk/test/ELF/Inputs/relocation-copy-relro.s Mon Jan 9 19:21:50 2017
@@ -0,0 +1,13 @@
+.rodata
+.globl a
+.size a, 4
+.type a, @object
+a:
+.word 1
+
+.section .data.rel.ro,"aw",%progbits
+.globl b
+.size b, 4
+.type b, @object
+b:
+.word 2
Added: lld/trunk/test/ELF/relocation-copy-relro.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/relocation-copy-relro.s?rev=291524&view=auto
==============================================================================
--- lld/trunk/test/ELF/relocation-copy-relro.s (added)
+++ lld/trunk/test/ELF/relocation-copy-relro.s Mon Jan 9 19:21:50 2017
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy-relro.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t.so
+// RUN: ld.lld %t.o %t.so -o %t3
+// RUN: llvm-readobj -program-headers -s -r %t3 | FileCheck %s
+
+// CHECK: Name: .bss.rel.ro (48)
+// CHECK-NEXT: Type: SHT_NOBITS (0x8)
+// CHECK-NEXT: Flags [ (0x3)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x2020B0
+// CHECK-NEXT: Offset: 0x20B0
+// CHECK-NEXT: Size: 8
+
+// CHECK: 0x2020B0 R_X86_64_COPY a 0x0
+// CHECK: 0x2020B4 R_X86_64_COPY b 0x0
+
+// CHECK: Type: PT_GNU_RELRO (0x6474E552)
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: VirtualAddress: 0x202000
+// CHECK-NEXT: PhysicalAddress: 0x202000
+// CHECK-NEXT: FileSize: 176
+// CHECK-NEXT: MemSize: 4096
+
+.text
+.global _start
+_start:
+movl $1, a
+movl $2, b
More information about the llvm-commits
mailing list