public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/nsz/pacbti-v5] rtld: Handle PT_GNU_PROPERTY
@ 2020-06-22 13:44 Szabolcs Nagy
  0 siblings, 0 replies; only message in thread
From: Szabolcs Nagy @ 2020-06-22 13:44 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=2fd3fdf54dcc9cf2c40808bf6b9b95a69038f929

commit 2fd3fdf54dcc9cf2c40808bf6b9b95a69038f929
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Mon Jun 22 10:56:38 2020 +0100

    rtld: Handle PT_GNU_PROPERTY
    
    Add generic code to handle PT_GNU_PROPERTY notes. Unlike
    _dl_process_pt_note, _dl_process_pt_gnu_property is generic,
    has no failure mode (invalid content is ignored) and always
    called after PT_LOAD segments are mapped. Currently only one
    NT_GNU_PROPERTY_TYPE_0 note is handled, which contains target
    specific properties: the _dl_process_gnu_property target hook
    is called for each property.
    
    Otherwise it follows the existing x86 note processing logic.

Diff:
---
 elf/dl-load.c              | 81 ++++++++++++++++++++++++++++++++++++++++++++++
 elf/rtld.c                 |  4 +++
 sysdeps/generic/dl-prop.h  | 19 ++++++++---
 sysdeps/generic/ldsodefs.h |  4 +++
 sysdeps/x86/dl-prop.h      |  7 ++++
 5 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 06f2ba7264..66bd0ca0a3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -853,6 +853,77 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
 }
 
 
+/* Process PT_GNU_PROPERTY program header PH in module L after
+   PT_LOAD segments are mapped.  Only one NT_GNU_PROPERTY_TYPE_0
+   note is handled which contains processor specific properties.  */
+
+void
+_dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph)
+{
+  const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
+  const ElfW(Addr) size = ph->p_memsz;
+  const ElfW(Addr) align = ph->p_align;
+
+  /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes in
+     32-bit objects and to 8 bytes in 64-bit objects.  Skip notes
+     with incorrect alignment.  */
+  if (align != (__ELF_NATIVE_CLASS / 8))
+    return;
+
+  const ElfW(Addr) start = (ElfW(Addr)) note;
+  unsigned int last_type = 0;
+
+  while ((ElfW(Addr)) (note + 1) - start < size)
+    {
+      /* Find the NT_GNU_PROPERTY_TYPE_0 note.  */
+      if (note->n_namesz == 4
+	  && note->n_type == NT_GNU_PROPERTY_TYPE_0
+	  && memcmp (note + 1, "GNU", 4) == 0)
+	{
+	  /* Check for invalid property.  */
+	  if (note->n_descsz < 8
+	      || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
+	    return;
+
+	  /* Start and end of property array.  */
+	  unsigned char *ptr = (unsigned char *) (note + 1) + 4;
+	  unsigned char *ptr_end = ptr + note->n_descsz;
+
+	  do
+	    {
+	      unsigned int type = *(unsigned int *) ptr;
+	      unsigned int datasz = *(unsigned int *) (ptr + 4);
+
+	      /* Property type must be in ascending order.  */
+	      if (type < last_type)
+		return;
+
+	      ptr += 8;
+	      if ((ptr + datasz) > ptr_end)
+		return;
+
+	      last_type = type;
+
+	      /* Target specific property processing.  */
+	      if (_dl_process_gnu_property(l, type, datasz, ptr) == 0)
+		return;
+
+	      /* Check the next property item.  */
+	      ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
+	    }
+	  while ((ptr_end - ptr) >= 8);
+
+	  /* Only handle one NT_GNU_PROPERTY_TYPE_0.  */
+	  return;
+	}
+
+      note = ((const void *) note
+	      + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
+				      align));
+    }
+}
+
+
 /* Map in the shared object NAME, actually located in REALNAME, and already
    opened on FD.  */
 
@@ -1188,6 +1259,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 				  maplength, has_holes, loader);
     if (__glibc_unlikely (errstring != NULL))
       goto call_lose;
+
+    /* Process program headers again after load segments are mapped in
+       case processing requires accessing those segments.  */
+    for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
+      switch (ph->p_type)
+	{
+	case PT_GNU_PROPERTY:
+	  _dl_process_pt_gnu_property (l, ph);
+	  break;
+	}
   }
 
   if (l->l_ld == 0)
diff --git a/elf/rtld.c b/elf/rtld.c
index 882b070cc0..3ad2bf5079 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1508,6 +1508,10 @@ of this helper program; chances are you did not intend to run this program.\n\
 	main_map->l_relro_size = ph->p_memsz;
 	break;
 
+      case PT_GNU_PROPERTY:
+	_dl_process_pt_gnu_property (main_map, ph);
+	break;
+
       case PT_NOTE:
 	if (_rtld_process_pt_note (main_map, ph))
 	  _dl_error_printf ("\
diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h
index 6b0f2aa95a..ceb6f623ee 100644
--- a/sysdeps/generic/dl-prop.h
+++ b/sysdeps/generic/dl-prop.h
@@ -20,11 +20,11 @@
 #define _DL_PROP_H
 
 /* The following functions are used by the dynamic loader and the
-   dlopen machinery to process PT_NOTE entries in the binary or
-   shared object.  The notes can be used to change the behaviour of
-   the loader, and as such offer a flexible mechanism for hooking in
-   various checks related to ABI tags or implementing "flag day" ABI
-   transitions.  */
+   dlopen machinery to process PT_NOTE and PT_GNU_PROPERTY entries in
+   the binary or shared object.  The notes can be used to change the
+   behaviour of the loader, and as such offer a flexible mechanism
+   for hooking in various checks related to ABI tags or implementing
+   "flag day" ABI transitions.  */
 
 static inline void __attribute__ ((always_inline))
 _rtld_main_check (struct link_map *m, const char *program)
@@ -51,4 +51,13 @@ _rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
   return 0;
 }
 
+/* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of L,
+   processing of the properties continues until this returns 0.  */
+static inline int __attribute__ ((always_inline))
+_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
+			  void *data)
+{
+  return 0;
+}
+
 #endif /* _DL_PROP_H */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index d08b97a5ef..c525ffa12c 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -910,6 +910,10 @@ extern void _dl_setup_hash (struct link_map *map) attribute_hidden;
 extern void _dl_rtld_di_serinfo (struct link_map *loader,
 				 Dl_serinfo *si, bool counting);
 
+/* Process PT_GNU_PROPERTY program header PH in module L after
+   PT_LOAD segments are mapped.  */
+void _dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph);
+
 
 /* Search loaded objects' symbol tables for a definition of the symbol
    referred to by UNDEF.  *SYM is the symbol table entry containing the
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index 516f88ea80..4a8ebc573e 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -191,4 +191,11 @@ _rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
   return 0;
 }
 
+static inline int __attribute__ ((always_inline))
+_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
+			  void *data)
+{
+  return 0;
+}
+
 #endif /* _DL_PROP_H */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-06-22 13:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-22 13:44 [glibc/nsz/pacbti-v5] rtld: Handle PT_GNU_PROPERTY Szabolcs Nagy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).