[v5,07/14] rtld: Handle PT_GNU_PROPERTY

Message ID 2fd3fdf54dcc9cf2c40808bf6b9b95a69038f929.1592834304.git.szabolcs.nagy@arm.com
State New
Headers show
Series
  • aarch64: branch protection support
Related show

Commit Message

Szabolcs Nagy June 22, 2020, 2 p.m.
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.
---
 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(-)

-- 
2.17.1

Comments

naohirot--- via Libc-alpha June 22, 2020, 8:41 p.m. | #1
On Mon, Jun 22, 2020 at 7:04 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>

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

> ---

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

> +       }

>    }

>


This patch is immediately changed by the next patch.  You should
combine them into
one patch and add

Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>

Thanks.

-- 
H.J.
Szabolcs Nagy June 25, 2020, 2:58 p.m. | #2
The 06/22/2020 13:41, H.J. Lu wrote:
> On Mon, Jun 22, 2020 at 7:04 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

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

> 

> This patch is immediately changed by the next patch.  You should

> combine them into

> one patch and add

> 

> Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>


in general i don't think a patch should be merged with a
previous patch just because it modifies something in it.

but in this case i'm fine either way so attached the
merged patch. (the content is unchanged only the
commit message updated to reflect the merge)

is this OK?
From 9033dc0b28d82773e053d7545beda3d70a64f123 Mon Sep 17 00:00:00 2001
From: Szabolcs Nagy <szabolcs.nagy@arm.com>

Date: Mon, 22 Jun 2020 10:56:38 +0100
Subject: [PATCH] rtld: Clean up PT_NOTE and add PT_GNU_PROPERTY handling

Add generic code to handle PT_GNU_PROPERTY notes. Invalid
content is ignored, _dl_process_pt_gnu_property is always called
after PT_LOAD segments are mapped and it has no failure modes.
Currently only one NT_GNU_PROPERTY_TYPE_0 note is handled, which
contains target specific properties: the _dl_process_gnu_property
hook is called for each property.

The old _dl_process_pt_note and _rtld_process_pt_note differ in how
the program header is read.  The old _dl_process_pt_note is called
before PT_LOAD segments are mapped and _rtld_process_pt_note is called
after PT_LOAD segments are mapped. The old _rtld_process_pt_note is
removed and _dl_process_pt_note is always called after PT_LOAD
segments are mapped and now it has no failure modes.

The program headers are scanned backwards so that PT_NOTE can be
skipped if PT_GNU_PROPERTY exists.

Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>
---
 elf/dl-load.c              | 94 ++++++++++++++++++++++++++++++++++----
 elf/rtld.c                 | 14 ++++--
 sysdeps/generic/dl-prop.h  | 23 +++++-----
 sysdeps/generic/ldsodefs.h |  4 ++
 sysdeps/x86/dl-prop.h      | 47 +++----------------
 5 files changed, 118 insertions(+), 64 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 06f2ba7264..32c74f79ef 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.  */
 
@@ -1145,14 +1216,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	  l->l_relro_addr = ph->p_vaddr;
 	  l->l_relro_size = ph->p_memsz;
 	  break;
-
-	case PT_NOTE:
-	  if (_dl_process_pt_note (l, ph, fd, fbp))
-	    {
-	      errstring = N_("cannot process note segment");
-	      goto call_lose;
-	    }
-	  break;
 	}
 
     if (__glibc_unlikely (nloadcmds == 0))
@@ -1188,6 +1251,21 @@ _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.  Scan program
+       headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY
+       exits.  */
+    for (ph = &phdr[l->l_phnum]; ph != phdr; --ph)
+      switch (ph[-1].p_type)
+	{
+	case PT_NOTE:
+	  _dl_process_pt_note (l, &ph[-1]);
+	  break;
+	case PT_GNU_PROPERTY:
+	  _dl_process_pt_gnu_property (l, &ph[-1]);
+	  break;
+	}
   }
 
   if (l->l_ld == 0)
diff --git a/elf/rtld.c b/elf/rtld.c
index 882b070cc0..f4c2602d65 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1507,11 +1507,17 @@ of this helper program; chances are you did not intend to run this program.\n\
 	main_map->l_relro_addr = ph->p_vaddr;
 	main_map->l_relro_size = ph->p_memsz;
 	break;
-
+      }
+  /* Process program headers again, but scan them backwards so
+     that PT_NOTE can be skipped if PT_GNU_PROPERTY exits.  */
+  for (ph = &phdr[phnum]; ph != phdr; --ph)
+    switch (ph[-1].p_type)
+      {
       case PT_NOTE:
-	if (_rtld_process_pt_note (main_map, ph))
-	  _dl_error_printf ("\
-ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+	_dl_process_pt_note (main_map, &ph[-1]);
+	break;
+      case PT_GNU_PROPERTY:
+	_dl_process_pt_gnu_property (main_map, &ph[-1]);
 	break;
       }
 
diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h
index 6b0f2aa95a..f1cf576fe3 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)
@@ -36,17 +36,16 @@ _dl_open_check (struct link_map *m)
 {
 }
 
-#ifdef FILEBUF_SIZE
-static inline int __attribute__ ((always_inline))
-_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
-		     int fd, struct filebuf *fbp)
+static inline void __attribute__ ((always_inline))
+_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
 {
-  return 0;
 }
-#endif
 
+/* 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))
-_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
+_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
+			  void *data)
 {
   return 0;
 }
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..89911e19e2 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -19,8 +19,6 @@
 #ifndef _DL_PROP_H
 #define _DL_PROP_H
 
-#include <not-cancel.h>
-
 extern void _dl_cet_check (struct link_map *, const char *)
     attribute_hidden;
 extern void _dl_cet_open_check (struct link_map *)
@@ -146,48 +144,17 @@ _dl_process_cet_property_note (struct link_map *l,
 #endif
 }
 
-#ifdef FILEBUF_SIZE
-static inline int __attribute__ ((unused))
-_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
-		     int fd, struct filebuf *fbp)
+static inline void __attribute__ ((unused))
+_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
 {
-# if CET_ENABLED
-  const ElfW(Nhdr) *note;
-  ElfW(Nhdr) *note_malloced = NULL;
-  ElfW(Addr) size = ph->p_filesz;
-
-  if (ph->p_offset + size <= (size_t) fbp->len)
-    note = (const void *) (fbp->buf + ph->p_offset);
-  else
-    {
-      if (size < __MAX_ALLOCA_CUTOFF)
-	note = alloca (size);
-      else
-	{
-	  note_malloced = malloc (size);
-	  note = note_malloced;
-	}
-      if (__pread64_nocancel (fd, (void *) note, size, ph->p_offset) != size)
-	{
-	  if (note_malloced)
-	    free (note_malloced);
-	  return -1;
-	}
-    }
-
-  _dl_process_cet_property_note (l, note, size, ph->p_align);
-  if (note_malloced)
-    free (note_malloced);
-# endif
-  return 0;
+  const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
+  _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
 }
-#endif
 
-static inline int __attribute__ ((unused))
-_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
+static inline int __attribute__ ((always_inline))
+_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
+			  void *data)
 {
-  const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
-  _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
   return 0;
 }
 
-- 
2.17.1
naohirot--- via Libc-alpha June 25, 2020, 3:25 p.m. | #3
On Thu, Jun 25, 2020 at 7:58 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>

> The 06/22/2020 13:41, H.J. Lu wrote:

> > On Mon, Jun 22, 2020 at 7:04 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

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

> >

> > This patch is immediately changed by the next patch.  You should

> > combine them into

> > one patch and add

> >

> > Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>

>

> in general i don't think a patch should be merged with a

> previous patch just because it modifies something in it.

>

> but in this case i'm fine either way so attached the

> merged patch. (the content is unchanged only the

> commit message updated to reflect the merge)

>

> is this OK?


LGTM.  I am working on a follow-up patch to implement
_dl_process_gnu_property.

Thanks.

-- 
H.J.
Szabolcs Nagy June 25, 2020, 3:43 p.m. | #4
The 06/25/2020 08:25, H.J. Lu wrote:
> On Thu, Jun 25, 2020 at 7:58 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

> > The 06/22/2020 13:41, H.J. Lu wrote:

> > > On Mon, Jun 22, 2020 at 7:04 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

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

> > >

> > > This patch is immediately changed by the next patch.  You should

> > > combine them into

> > > one patch and add

> > >

> > > Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>

> >

> > in general i don't think a patch should be merged with a

> > previous patch just because it modifies something in it.

> >

> > but in this case i'm fine either way so attached the

> > merged patch. (the content is unchanged only the

> > commit message updated to reflect the merge)

> >

> > is this OK?

> 

> LGTM.  I am working on a follow-up patch to implement

> _dl_process_gnu_property.


OK, i will wait a bit in case somebody has a comment
e.g. about the backward iteration over phdr.

if there are no comments i'll commit this tomorrow.
naohirot--- via Libc-alpha June 25, 2020, 7:14 p.m. | #5
On Thu, Jun 25, 2020 at 8:43 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:
>

> The 06/25/2020 08:25, H.J. Lu wrote:

> > On Thu, Jun 25, 2020 at 7:58 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

> > > The 06/22/2020 13:41, H.J. Lu wrote:

> > > > On Mon, Jun 22, 2020 at 7:04 AM Szabolcs Nagy <szabolcs.nagy@arm.com> wrote:

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

> > > >

> > > > This patch is immediately changed by the next patch.  You should

> > > > combine them into

> > > > one patch and add

> > > >

> > > > Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>

> > >

> > > in general i don't think a patch should be merged with a

> > > previous patch just because it modifies something in it.

> > >

> > > but in this case i'm fine either way so attached the

> > > merged patch. (the content is unchanged only the

> > > commit message updated to reflect the merge)

> > >

> > > is this OK?

> >

> > LGTM.  I am working on a follow-up patch to implement

> > _dl_process_gnu_property.

>

> OK, i will wait a bit in case somebody has a comment

> e.g. about the backward iteration over phdr.

>

> if there are no comments i'll commit this tomorrow.


Here is a patch to implement _dl_process_gnu_property for x86.
I added _dl_process_pt_gnu_property_start to set the l_cet field
to lc_none before scanning GNU property to indicate that CET
status is no longer unknown.

-- 
H.J.

Patch

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 */