diff mbox

Read-only data in ELF libraries may be remapped writable at runtime (upcoming NDSS'17 paper)

Message ID 20161224002314.GH2896@bubble.grove.modra.org
State RFC, archived
Headers show

Commit Message

Alan Modra Dec. 24, 2016, 12:23 a.m. UTC
On Fri, Dec 23, 2016 at 08:02:22PM +0100, Florian Weimer wrote:
> On 12/23/2016 07:32 PM, Mathias Payer wrote:
> >
> >
> >On December 23, 2016 7:18:29 PM GMT+01:00, Florian Weimer <fweimer@redhat.com> wrote:
> >>On 12/23/2016 07:04 PM, Mathias Payer wrote:
> >>
> >>>At the linker level you likely don't know if the referenced symbol is
> >>RO
> >>>or not (as it could come from any object) -- only the runtime loader
> >>has
> >>>this knowledge and at that time it is too late as PIE uses relative
> >>>addressing inside the object.
> >>
> >>The static linker necessarily sees a definition, otherwise it cannot
> >>produce a copy relocation because copy relocations must refer to
> >>objects
> >>of known size.
> >
> >Agreed. The static linker knows about the symbol and size but not the permission. That information is discarded after compilation.
> 
> That's not quite true.  At least in the vtable case, the vtable is emitted
> in the .data.rel.ro section, and this information is definitely available to
> the static linker.

I believe that should be the case for all dynamic symbols of interest.

Here's a prototype patch for powerpc64.  Obviously there's a lot more
work to do yet to fix all the other backends.
diff mbox

Patch

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2f0aaf6..e1f4566 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -595,6 +595,10 @@  struct elf_link_hash_table
   asection *srelgot;
   asection *splt;
   asection *srelplt;
+  asection *sdynbss;
+  asection *srelbss;
+  asection *sdynrelro;
+  asection *srelro;
   asection *igotplt;
   asection *iplt;
   asection *irelplt;
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index ae014e5..b9cb378 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -93,7 +93,7 @@  static bfd_vma opd_entry_value
 #define elf_backend_grok_prstatus	      ppc64_elf_grok_prstatus
 #define elf_backend_grok_psinfo		      ppc64_elf_grok_psinfo
 #define elf_backend_write_core_note	      ppc64_elf_write_core_note
-#define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
+#define elf_backend_create_dynamic_sections   _bfd_elf_create_dynamic_sections
 #define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
 #define elf_backend_add_symbol_hook	      ppc64_elf_add_symbol_hook
 #define elf_backend_check_directives	      ppc64_elf_before_check_relocs
@@ -4084,8 +4084,6 @@  struct ppc_link_hash_table
   struct ppc_link_hash_entry *dot_syms;
 
   /* Shortcuts to get to dynamic linker sections.  */
-  asection *dynbss;
-  asection *relbss;
   asection *glink;
   asection *sfpr;
   asection *brlt;
@@ -4669,31 +4667,6 @@  create_got_section (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
-/* Create the dynamic sections, and set up shortcuts.  */
-
-static bfd_boolean
-ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
-{
-  struct ppc_link_hash_table *htab;
-
-  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
-    return FALSE;
-
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
-  htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!bfd_link_pic (info))
-    htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
-  if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss
-      || (!bfd_link_pic (info) && !htab->relbss))
-    abort ();
-
-  return TRUE;
-}
-
 /* Follow indirect and warning symbol links.  */
 
 static inline struct bfd_link_hash_entry *
@@ -7311,7 +7284,7 @@  ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 				 struct elf_link_hash_entry *h)
 {
   struct ppc_link_hash_table *htab;
-  asection *s;
+  asection *s, *srel;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
@@ -7441,14 +7414,22 @@  ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      to copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
      .rela.bss section we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->elf.sdynrelro;
+      srel = htab->elf.srelro;
+    }
+  else
+    {
+      s = htab->elf.sdynbss;
+      srel = htab->elf.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
-      htab->relbss->size += sizeof (Elf64_External_Rela);
+      srel->size += sizeof (Elf64_External_Rela);
       h->needs_copy = 1;
     }
 
-  s = htab->dynbss;
-
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
@@ -10278,7 +10259,8 @@  ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 	       || s == htab->elf.splt
 	       || s == htab->elf.iplt
 	       || s == htab->glink
-	       || s == htab->dynbss)
+	       || s == htab->elf.sdynbss
+	       || s == htab->elf.sdynrelro)
 	{
 	  /* Strip this section if we don't need it; see the
 	     comment below.  */
@@ -10331,7 +10313,7 @@  ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 	 but this way if it does we get a R_PPC64_NONE reloc in .rela
 	 sections instead of garbage.
 	 We also rely on the section contents being zero when writing
-	 the GOT.  */
+	 the GOT and .dynrelro.  */
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
 	return FALSE;
@@ -15615,11 +15597,13 @@  ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
+      asection *srel;
 
       if (h->dynindx == -1
 	  || (h->root.type != bfd_link_hash_defined
 	      && h->root.type != bfd_link_hash_defweak)
-	  || htab->relbss == NULL)
+	  || htab->elf.srelbss == NULL
+	  || htab->elf.srelro == NULL)
 	abort ();
 
       rela.r_offset = (h->root.u.def.value
@@ -15627,8 +15611,12 @@  ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 		       + h->root.u.def.section->output_offset);
       rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
       rela.r_addend = 0;
-      loc = htab->relbss->contents;
-      loc += htab->relbss->reloc_count++ * sizeof (Elf64_External_Rela);
+      if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+	srel = htab->elf.srelro;
+      else
+	srel = htab->elf.srelbss;
+      loc = srel->contents;
+      loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 42bb837..a10ed07 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -427,6 +427,17 @@  _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 					      (SEC_ALLOC | SEC_LINKER_CREATED));
       if (s == NULL)
 	return FALSE;
+      htab->sdynbss = s;
+
+      /* Similarly, but for symbols that were originally in read-only
+	 sections.  */
+      s = bfd_make_section_anyway_with_flags (abfd, ".dynrelro",
+					      (SEC_ALLOC | SEC_READONLY
+					       | SEC_HAS_CONTENTS
+					       | SEC_LINKER_CREATED));
+      if (s == NULL)
+	return FALSE;
+      htab->sdynrelro = s;
 
       /* The .rel[a].bss section holds copy relocs.  This section is not
 	 normally needed.  We need to create it here, though, so that the
@@ -448,6 +459,16 @@  _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 	  if (s == NULL
 	      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
 	    return FALSE;
+	  htab->srelbss = s;
+
+	  s = bfd_make_section_anyway_with_flags (abfd,
+						  (bed->rela_plts_and_copies_p
+						   ? ".rela.ro" : ".rel.ro"),
+						  flags | SEC_READONLY);
+	  if (s == NULL
+	      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+	    return FALSE;
+	  htab->srelro = s;
 	}
     }
 
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index f0c6439..12cfe8b 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -169,7 +169,7 @@  RELA_IPLT=".rela.iplt    ${RELOCATING-0} :
     }"
 DYNAMIC=".dynamic      ${RELOCATING-0} : { *(.dynamic) }"
 RODATA=".${RODATA_NAME}       ${RELOCATING-0} : { *(.${RODATA_NAME}${RELOCATING+ .${RODATA_NAME}.* .gnu.linkonce.r.*}) }"
-DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }"
+DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) *(.dynrelro) }"
 DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
 if test -z "${NO_SMALL_DATA}"; then
   SBSS=".${SBSS_NAME}         ${RELOCATING-0} :