[PATCH] D33251: [lld][ELF]Add option to make .dynamic read only

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Wed May 17 22:17:57 PDT 2017


You can't use a processor specific flag for this. The number can mean
something else in another processor.

I thought another reason for .dynamic to be rw is to allow a dynamic
linker to modify d_ptr values in place to point to the runtime
address. Not sure if that is done in practice.

Cheers,
Rafael

Jake Ehrlich via Phabricator via llvm-commits
<llvm-commits at lists.llvm.org> writes:

> jakehehrlich created this revision.
> jakehehrlich added a project: lld.
> Herald added a subscriber: arichardson.
>
> The .dynamic section of an ELF almost doesn't need to be written to with the exception of the DT_DEBUG entry. For security reasons having a read only .dynamic section would be useful. MIPS already uses a solution to this that adds an address to a separate writable section. This change adds support for this option on non-MIPS targets. To make names not be MIPS specific MipsRldMapSection was made RldMapSection and DT_MIPS_RLD_MAP has the alternate name of DT_DEBUG_INDIRECT. To make non-MIPS targets emit a read only .dynamic section there is a -z keyword "rodynamic" which sets the appropriate flag. This flag is always set on MIPS.
>
>
> Repository:
>   rL LLVM
>
> https://reviews.llvm.org/D33251
>
> Files:
>   ELF/Config.h
>   ELF/Driver.cpp
>   ELF/SyntheticSections.cpp
>   ELF/SyntheticSections.h
>   ELF/Writer.cpp
>   test/ELF/Inputs/rodynamic.s
>   test/ELF/rodynamic.s
>
> Index: test/ELF/rodynamic.s
> ===================================================================
> --- /dev/null
> +++ test/ELF/rodynamic.s
> @@ -0,0 +1,27 @@
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/rodynamic.s -o %td.o
> +# RUN: ld.lld -shared %td.o -o %td.so
> +# RUN: ld.lld -z rodynamic %t.o %td.so -o %t.exe
> +# RUN: llvm-readobj -sections -dynamic-table %t.exe | FileCheck %s
> +
> +  .text
> +  .globl __start,_foo
> +  .type _foo, at function
> +__start:
> +  ret
> +
> +# CHECK:        Section {
> +# CHECK:          Name: .dynamic
> +# CHECK-NEXT:     Type: SHT_DYNAMIC
> +# CHECK-NEXT:     Flags [
> +# CHECK-NEXT:       SHF_ALLOC
> +# CHECK-NEXT:     ]
> +# CHECK:          Name: .rld_map
> +# CHECK-NEXT:     Type: SHT_PROGBITS
> +# CHECK-NEXT:     Flags [
> +# CHECK-NEXT:       SHF_ALLOC
> +# CHECK-NEXT:       SHF_WRITE
> +# CHECK-NEXT:     ]
> +# CHECK-NEXT:     Address: [[RLDMAPADDR:0x[0-9a-f]+]]
> +# CHECK:        DynamicSection [
> +# CHECK:          0x0000000070000016 unknown [[RLDMAPADDR]]
> Index: test/ELF/Inputs/rodynamic.s
> ===================================================================
> --- /dev/null
> +++ test/ELF/Inputs/rodynamic.s
> @@ -0,0 +1,4 @@
> +  .text
> +  .globl _foo
> +_foo:
> +  ret
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -355,18 +355,21 @@
>    bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() ||
>                        Config->Pic || Config->ExportDynamic;
>    if (Config->EMachine == EM_MIPS) {
> -    if (!Config->Shared && HasDynSymTab) {
> -      InX::MipsRldMap = make<MipsRldMapSection>();
> -      Add(InX::MipsRldMap);
> -    }
>      if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
>        Add(Sec);
>      if (auto *Sec = MipsOptionsSection<ELFT>::create())
>        Add(Sec);
>      if (auto *Sec = MipsReginfoSection<ELFT>::create())
>        Add(Sec);
>    }
>  
> +  //If ZReadOnlyDynamic is set then we're going to need to emit a
> +  //RldMapSection for DT_DEBUG_INDIRECT/DT_MIPS_RLD_MAP to point to.
> +  if(!Config->Shared && HasDynSymTab && Config->ZReadOnlyDynamic) {
> +    In<ELFT>::RldMap = make<RldMapSection>();
> +    Add(In<ELFT>::RldMap);
> +  }
> +
>    if (HasDynSymTab) {
>      In<ELFT>::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
>      Add(In<ELFT>::DynSymTab);
> Index: ELF/SyntheticSections.h
> ===================================================================
> --- ELF/SyntheticSections.h
> +++ ELF/SyntheticSections.h
> @@ -336,6 +336,19 @@
>    int64_t Addend;
>  };
>  
> +// This is a section to hold a space within the data segment
> +// of the executable file which is pointed to by the
> +// DT_MIPS_RLD_MAP/DT_DEBUG_INDIRECT entry. This was a MIPS specific
> +// section but it has other uses as well.
> +// See "Dynamic section" in Chapter 5 in the following document:
> +// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> +class RldMapSection : public SyntheticSection {
> +public:
> +  RldMapSection();
> +  size_t getSize() const override { return Config->Wordsize; }
> +  void writeTo(uint8_t *Buf) override;
> +};
> +
>  template <class ELFT> class DynamicSection final : public SyntheticSection {
>    typedef typename ELFT::Dyn Elf_Dyn;
>    typedef typename ELFT::Rel Elf_Rel;
> @@ -701,17 +714,6 @@
>    Elf_Mips_RegInfo Reginfo;
>  };
>  
> -// This is a MIPS specific section to hold a space within the data segment
> -// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
> -// See "Dynamic section" in Chapter 5 in the following document:
> -// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> -class MipsRldMapSection : public SyntheticSection {
> -public:
> -  MipsRldMapSection();
> -  size_t getSize() const override { return Config->Wordsize; }
> -  void writeTo(uint8_t *Buf) override;
> -};
> -
>  class ARMExidxSentinelSection : public SyntheticSection {
>  public:
>    ARMExidxSentinelSection();
> @@ -762,7 +764,7 @@
>    static GotPltSection *GotPlt;
>    static IgotPltSection *IgotPlt;
>    static MipsGotSection *MipsGot;
> -  static MipsRldMapSection *MipsRldMap;
> +  static RldMapSection *RldMap;
>    static PltSection *Plt;
>    static PltSection *Iplt;
>    static StringTableSection *ShStrTab;
> Index: ELF/SyntheticSections.cpp
> ===================================================================
> --- ELF/SyntheticSections.cpp
> +++ ELF/SyntheticSections.cpp
> @@ -999,6 +999,21 @@
>    }
>  }
>  
> +RldMapSection::RldMapSection()
> +    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
> +                       ".rld_map") {}
> +
> +void RldMapSection::writeTo(uint8_t *Buf) {
> +  // Apply filler from linker script.
> +  Optional<uint32_t> Fill = Script->getFiller(this->OutSec);
> +  if (!Fill || *Fill == 0)
> +    return;
> +
> +  uint64_t Filler = *Fill;
> +  Filler = (Filler << 32) | Filler;
> +  memcpy(Buf, &Filler, getSize());
> +}
> +
>  // Returns the number of version definition entries. Because the first entry
>  // is for the version definition itself, it is the number of versioned symbols
>  // plus one. Note that we don't support multiple versions yet.
> @@ -1010,10 +1025,11 @@
>                         ".dynamic") {
>    this->Entsize = ELFT::Is64Bits ? 16 : 8;
>  
> -  // .dynamic section is not writable on MIPS.
> +  // For security the user may want to make .dynamic read only.
> +  // Additionally .dynamic section is not writable on MIPS.
>    // See "Special Section" in Chapter 4 in the following document:
>    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
> -  if (Config->EMachine == EM_MIPS)
> +  if (Config->ZReadOnlyDynamic)
>      this->Flags = SHF_ALLOC;
>  
>    addEntries();
> @@ -1058,7 +1074,8 @@
>    if (DtFlags1)
>      add({DT_FLAGS_1, DtFlags1});
>  
> -  if (!Config->Shared && !Config->Relocatable)
> +  //If .dynamic is read only then DT_DEBUG will cause a segfault.
> +  if (!Config->Shared && !Config->Relocatable && !Config->ZReadOnlyDynamic)
>      add({DT_DEBUG, (uint64_t)0});
>  }
>  
> @@ -1144,9 +1161,9 @@
>      else
>        add({DT_MIPS_GOTSYM, In<ELFT>::DynSymTab->getNumSymbols()});
>      add({DT_PLTGOT, InX::MipsGot});
> -    if (InX::MipsRldMap)
> -      add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
>    }
> +  if (InX::RldMap)
> +    add({DT_DEBUG_INDIRECT, InX::RldMap});
>  
>    this->OutSec->Link = this->Link;
>  
> @@ -2177,21 +2194,6 @@
>    return Builder.getSize();
>  }
>  
> -MipsRldMapSection::MipsRldMapSection()
> -    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
> -                       ".rld_map") {}
> -
> -void MipsRldMapSection::writeTo(uint8_t *Buf) {
> -  // Apply filler from linker script.
> -  Optional<uint32_t> Fill = Script->getFiller(this->OutSec);
> -  if (!Fill || *Fill == 0)
> -    return;
> -
> -  uint64_t Filler = *Fill;
> -  Filler = (Filler << 32) | Filler;
> -  memcpy(Buf, &Filler, getSize());
> -}
> -
>  ARMExidxSentinelSection::ARMExidxSentinelSection()
>      : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
>                         Config->Wordsize, ".ARM.exidx") {}
> @@ -2249,7 +2251,7 @@
>  GotPltSection *InX::GotPlt;
>  IgotPltSection *InX::IgotPlt;
>  MipsGotSection *InX::MipsGot;
> -MipsRldMapSection *InX::MipsRldMap;
> +RldMapSection *InX::RldMap;
>  PltSection *InX::Plt;
>  PltSection *InX::Iplt;
>  StringTableSection *InX::ShStrTab;
> Index: ELF/Driver.cpp
> ===================================================================
> --- ELF/Driver.cpp
> +++ ELF/Driver.cpp
> @@ -687,6 +687,7 @@
>    Config->ZNodlopen = hasZOption(Args, "nodlopen");
>    Config->ZNow = hasZOption(Args, "now");
>    Config->ZOrigin = hasZOption(Args, "origin");
> +  Config->ZReadOnlyDynamic = hasZOption(Args, "rodynamic");
>    Config->ZRelro = !hasZOption(Args, "norelro");
>    Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
>    Config->ZText = !hasZOption(Args, "notext");
> @@ -787,6 +788,8 @@
>    Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
>    Config->Pic = Config->Pie || Config->Shared;
>    Config->Wordsize = Config->Is64 ? 8 : 4;
> +  //MIPS must unconditionally set ZReadOnlyDynamic
> +  Config->ZReadOnlyDynamic = Machine == EM_MIPS ? true : Config->ZReadOnlyDynamic;
>  }
>  
>  // Returns a value of "-format" option.
> Index: ELF/Config.h
> ===================================================================
> --- ELF/Config.h
> +++ ELF/Config.h
> @@ -144,6 +144,7 @@
>    bool ZNodlopen;
>    bool ZNow;
>    bool ZOrigin;
> +  bool ZReadOnlyDynamic;
>    bool ZRelro;
>    bool ZText;
>    bool ExitEarly;
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list