Blame SOURCES/elfutils-0.174-gnu-property-note.patch

95a93d
commit 5199e15870e05e5b0b9f98c20fc9b5427aa6dd6a
95a93d
Author: Mark Wielaard <mark@klomp.org>
95a93d
Date:   Mon Oct 15 23:35:47 2018 +0200
95a93d
95a93d
    Recognize and parse GNU Property notes.
95a93d
    
95a93d
    GNU Property notes are different from normal notes because they use
95a93d
    variable alignment/padding of their fields. They are 8 byte aligned,
95a93d
    but use 4 byte fields. The name is aligned at 4 bytes and padded so
95a93d
    that, the desc is aligned at 8 bytes. The whole note is padded to
95a93d
    8 bytes again. For normal notes all fields are both 4 bytes wide and
95a93d
    4 bytes aligned.
95a93d
    
95a93d
    To recognize these new kind of ELF Notes a new Elf_Type is introduced,
95a93d
    ELF_T_NHDR8. This type is used in the xlate functions to determine
95a93d
    how to align and pad the various fields. Since the fields themselves
95a93d
    can now have different alignments we will have to keep track of the
95a93d
    current alignement and use either NOTE_ALIGN4 or NOTE_ALIGN8 to
95a93d
    determine the padding.
95a93d
    
95a93d
    To set the correct Elf_Type on the Elf_Data we use either the section
95a93d
    sh_addralign or the segment p_align values. Assuming 8 means the
95a93d
    section or segment contains the new style notes, otherwise normal
95a93d
    notes.
95a93d
    
95a93d
    When we cannot determine the "alignment" directly, like when parsing
95a93d
    special kernel sys files, we check the name "GNU" and type
95a93d
    "GNU_PROPERTY_TYPE_0" fields.
95a93d
    
95a93d
    ebl_object_note now parses the new NT_GNU_PROPERTY_TYPE_0 and can
95a93d
    extract the GNU_PROPERTY_STACK_SIZE, GNU_PROPERTY_NO_COPY_ON_PROTECTED
95a93d
    and GNU_PROPERTY_X86_FEATURE_1_AND types GNU_PROPERTY_X86_FEATURE_1_IBT
95a93d
    and GNU_PROPERTY_X86_FEATURE_1_SHSTK.
95a93d
    
95a93d
    Tests are added for extracting the note from sections or segments
95a93d
    as set by gcc -fcf-protection.
95a93d
    
95a93d
    Signed-off-by: Mark Wielaard <mark@klomp.org>
95a93d
95a93d
diff --git a/libdwelf/dwelf_elf_gnu_build_id.c b/libdwelf/dwelf_elf_gnu_build_id.c
95a93d
index 8c78c70..dbcfc82 100644
95a93d
--- a/libdwelf/dwelf_elf_gnu_build_id.c
95a93d
+++ b/libdwelf/dwelf_elf_gnu_build_id.c
95a93d
@@ -88,7 +88,9 @@ find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
95a93d
 	    result = check_notes (elf_getdata_rawchunk (elf,
95a93d
 							phdr->p_offset,
95a93d
 							phdr->p_filesz,
95a93d
-							ELF_T_NHDR),
95a93d
+							(phdr->p_align == 8
95a93d
+							 ? ELF_T_NHDR8
95a93d
+							 : ELF_T_NHDR)),
95a93d
 				  phdr->p_vaddr,
95a93d
 				  build_id_bits,
95a93d
 				  build_id_elfaddr,
95a93d
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
95a93d
index 84cb89a..01109f4 100644
95a93d
--- a/libdwfl/core-file.c
95a93d
+++ b/libdwfl/core-file.c
95a93d
@@ -496,7 +496,9 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
95a93d
       Elf_Data *notes = elf_getdata_rawchunk (elf,
95a93d
 					      notes_phdr.p_offset,
95a93d
 					      notes_phdr.p_filesz,
95a93d
-					      ELF_T_NHDR);
95a93d
+					      (notes_phdr.p_align == 8
95a93d
+					       ? ELF_T_NHDR8
95a93d
+					       : ELF_T_NHDR));
95a93d
       if (likely (notes != NULL))
95a93d
 	{
95a93d
 	  size_t pos = 0;
95a93d
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
95a93d
index 8749884..0d633ff 100644
95a93d
--- a/libdwfl/dwfl_segment_report_module.c
95a93d
+++ b/libdwfl/dwfl_segment_report_module.c
95a93d
@@ -27,7 +27,7 @@
95a93d
    not, see <http://www.gnu.org/licenses/>.  */
95a93d
 
95a93d
 #include <config.h>
95a93d
-#include "../libelf/libelfP.h"	/* For NOTE_ALIGN.  */
95a93d
+#include "../libelf/libelfP.h"	/* For NOTE_ALIGN4 and NOTE_ALIGN8.  */
95a93d
 #undef	_
95a93d
 #include "libdwflP.h"
95a93d
 #include "common.h"
95a93d
@@ -451,7 +451,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
95a93d
   GElf_Addr build_id_vaddr = 0;
95a93d
 
95a93d
   /* Consider a PT_NOTE we've found in the image.  */
95a93d
-  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
95a93d
+  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz,
95a93d
+			      GElf_Xword align)
95a93d
   {
95a93d
     /* If we have already seen a build ID, we don't care any more.  */
95a93d
     if (build_id != NULL || filesz == 0)
95a93d
@@ -478,7 +479,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
95a93d
 	notes = malloc (filesz);
95a93d
 	if (unlikely (notes == NULL))
95a93d
 	  return;
95a93d
-	xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
95a93d
+	xlatefrom.d_type = xlateto.d_type = (align == 8
95a93d
+					     ? ELF_T_NHDR8 : ELF_T_NHDR);
95a93d
 	xlatefrom.d_buf = (void *) data;
95a93d
 	xlatefrom.d_size = filesz;
95a93d
 	xlateto.d_buf = notes;
95a93d
@@ -489,15 +491,23 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
95a93d
       }
95a93d
 
95a93d
     const GElf_Nhdr *nh = notes;
95a93d
-    while ((const void *) nh < (const void *) notes + filesz)
95a93d
-     {
95a93d
-	const void *note_name = nh + 1;
95a93d
-	const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
95a93d
-	if (unlikely ((size_t) ((const void *) notes + filesz
95a93d
-				- note_desc) < nh->n_descsz))
95a93d
+    size_t len = 0;
95a93d
+    while (filesz > len + sizeof (*nh))
95a93d
+      {
95a93d
+	const void *note_name;
95a93d
+	const void *note_desc;
95a93d
+
95a93d
+	len += sizeof (*nh);
95a93d
+	note_name = notes + len;
95a93d
+
95a93d
+	len += nh->n_namesz;
95a93d
+	len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
95a93d
+	note_desc = notes + len;
95a93d
+
95a93d
+	if (unlikely (filesz < len + nh->n_descsz))
95a93d
 	  break;
95a93d
 
95a93d
-	if (nh->n_type == NT_GNU_BUILD_ID
95a93d
+        if (nh->n_type == NT_GNU_BUILD_ID
95a93d
 	    && nh->n_descsz > 0
95a93d
 	    && nh->n_namesz == sizeof "GNU"
95a93d
 	    && !memcmp (note_name, "GNU", sizeof "GNU"))
95a93d
@@ -510,7 +520,9 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
95a93d
 	    break;
95a93d
 	  }
95a93d
 
95a93d
-	nh = note_desc + NOTE_ALIGN (nh->n_descsz);
95a93d
+	len += nh->n_descsz;
95a93d
+	len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
95a93d
+	nh = (void *) notes + len;
95a93d
       }
95a93d
 
95a93d
   done:
95a93d
@@ -535,7 +547,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
95a93d
       case PT_NOTE:
95a93d
 	/* We calculate from the p_offset of the note segment,
95a93d
 	   because we don't yet know the bias for its p_vaddr.  */
95a93d
-	consider_notes (start + offset, filesz);
95a93d
+	consider_notes (start + offset, filesz, align);
95a93d
 	break;
95a93d
 
95a93d
       case PT_LOAD:
95a93d
diff --git a/libdwfl/linux-core-attach.c b/libdwfl/linux-core-attach.c
95a93d
index 9f05f72..6c99b9e 100644
95a93d
--- a/libdwfl/linux-core-attach.c
95a93d
+++ b/libdwfl/linux-core-attach.c
95a93d
@@ -355,7 +355,9 @@ dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
95a93d
       if (phdr != NULL && phdr->p_type == PT_NOTE)
95a93d
 	{
95a93d
 	  note_data = elf_getdata_rawchunk (core, phdr->p_offset,
95a93d
-					    phdr->p_filesz, ELF_T_NHDR);
95a93d
+					    phdr->p_filesz, (phdr->p_align == 8
95a93d
+							     ? ELF_T_NHDR8
95a93d
+							     : ELF_T_NHDR));
95a93d
 	  break;
95a93d
 	}
95a93d
     }
95a93d
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
95a93d
index 9d0fef2..360e4ee 100644
95a93d
--- a/libdwfl/linux-kernel-modules.c
95a93d
+++ b/libdwfl/linux-kernel-modules.c
95a93d
@@ -39,6 +39,7 @@
95a93d
 #include <config.h>
95a93d
 #include <system.h>
95a93d
 
95a93d
+#include "libelfP.h"
95a93d
 #include "libdwflP.h"
95a93d
 #include <inttypes.h>
95a93d
 #include <errno.h>
95a93d
@@ -554,15 +555,41 @@ check_notes (Dwfl_Module *mod, const char *notesfile,
95a93d
     return 1;
95a93d
 
95a93d
   unsigned char *p = buf.data;
95a93d
+  size_t len = 0;
95a93d
   while (p < &buf.data[n])
95a93d
     {
95a93d
       /* No translation required since we are reading the native kernel.  */
95a93d
       GElf_Nhdr *nhdr = (void *) p;
95a93d
-      p += sizeof *nhdr;
95a93d
+      len += sizeof *nhdr;
95a93d
+      p += len;
95a93d
       unsigned char *name = p;
95a93d
-      p += (nhdr->n_namesz + 3) & -4U;
95a93d
-      unsigned char *bits = p;
95a93d
-      p += (nhdr->n_descsz + 3) & -4U;
95a93d
+      unsigned char *bits;
95a93d
+      /* This is somewhat ugly, GNU Property notes use different padding,
95a93d
+	 but all we have is the file content, so we have to actually check
95a93d
+	 the name and type.  */
95a93d
+      if (nhdr->n_type == NT_GNU_PROPERTY_TYPE_0
95a93d
+          && nhdr->n_namesz == sizeof "GNU"
95a93d
+          && name + nhdr->n_namesz < &buf.data[n]
95a93d
+          && !memcmp (name, "GNU", sizeof "GNU"))
95a93d
+	{
95a93d
+	  len += nhdr->n_namesz;
95a93d
+	  len = NOTE_ALIGN8 (len);
95a93d
+	  p = buf.data + len;
95a93d
+	  bits = p;
95a93d
+	  len += nhdr->n_descsz;
95a93d
+	  len = NOTE_ALIGN8 (len);
95a93d
+	  p = buf.data + len;
95a93d
+	}
95a93d
+      else
95a93d
+	{
95a93d
+	  len += nhdr->n_namesz;
95a93d
+	  len = NOTE_ALIGN4 (len);
95a93d
+	  p = buf.data + len;
95a93d
+	  bits = p;
95a93d
+	  len += nhdr->n_descsz;
95a93d
+	  len = NOTE_ALIGN4 (len);
95a93d
+	  p = buf.data + len;
95a93d
+	}
95a93d
 
95a93d
       if (p <= &buf.data[n]
95a93d
 	  && nhdr->n_type == NT_GNU_BUILD_ID
95a93d
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
95a93d
index ca4f155..57e9f52 100644
95a93d
--- a/libebl/eblobjnote.c
95a93d
+++ b/libebl/eblobjnote.c
95a93d
@@ -1,5 +1,5 @@
95a93d
 /* Print contents of object file note.
95a93d
-   Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016 Red Hat, Inc.
95a93d
+   Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016, 2018 Red Hat, Inc.
95a93d
    This file is part of elfutils.
95a93d
    Written by Ulrich Drepper <drepper@redhat.com>, 2002.
95a93d
 
95a93d
@@ -37,6 +37,8 @@
95a93d
 #include <string.h>
95a93d
 #include <libeblP.h>
95a93d
 
95a93d
+#include "libelfP.h"
95a93d
+
95a93d
 
95a93d
 void
95a93d
 ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
95a93d
@@ -153,6 +155,187 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
95a93d
 		    (int) descsz, desc);
95a93d
 	  break;
95a93d
 
95a93d
+	case NT_GNU_PROPERTY_TYPE_0:
95a93d
+	  if (strcmp (name, "GNU") == 0 && descsz > 0)
95a93d
+	    {
95a93d
+	      /* There are at least 2 words. type and datasz.  */
95a93d
+	      while (descsz >= 8)
95a93d
+		{
95a93d
+		  struct pr_prop
95a93d
+		  {
95a93d
+		    GElf_Word pr_type;
95a93d
+		    GElf_Word pr_datasz;
95a93d
+		  } prop;
95a93d
+
95a93d
+		  Elf_Data in =
95a93d
+		    {
95a93d
+		      .d_version = EV_CURRENT,
95a93d
+		      .d_type = ELF_T_WORD,
95a93d
+		      .d_size = 8,
95a93d
+		      .d_buf = (void *) desc
95a93d
+		    };
95a93d
+		  Elf_Data out =
95a93d
+		    {
95a93d
+		      .d_version = EV_CURRENT,
95a93d
+		      .d_type = ELF_T_WORD,
95a93d
+		      .d_size = descsz,
95a93d
+		      .d_buf = (void *) &prop
95a93d
+		    };
95a93d
+
95a93d
+		  if (gelf_xlatetom (ebl->elf, &out, &in,
95a93d
+				     elf_getident (ebl->elf,
95a93d
+						   NULL)[EI_DATA]) == NULL)
95a93d
+		    {
95a93d
+		      printf ("%s\n", elf_errmsg (-1));
95a93d
+		      return;
95a93d
+		    }
95a93d
+
95a93d
+		  desc += 8;
95a93d
+		  descsz -= 8;
95a93d
+
95a93d
+		  int elfclass = gelf_getclass (ebl->elf);
95a93d
+		  char *elfident = elf_getident (ebl->elf, NULL);
95a93d
+		  GElf_Ehdr ehdr;
95a93d
+		  gelf_getehdr (ebl->elf, &ehdr);
95a93d
+
95a93d
+		  /* Prefix.  */
95a93d
+		  printf ("    ");
95a93d
+		  if (prop.pr_type == GNU_PROPERTY_STACK_SIZE)
95a93d
+		    {
95a93d
+		      printf ("STACK_SIZE ");
95a93d
+		      if (prop.pr_datasz == 4 || prop.pr_datasz == 8)
95a93d
+			{
95a93d
+			  GElf_Addr addr;
95a93d
+			  in.d_type = ELF_T_ADDR;
95a93d
+			  out.d_type = ELF_T_ADDR;
95a93d
+			  in.d_size = prop.pr_datasz;
95a93d
+			  out.d_size = sizeof (addr);
95a93d
+			  in.d_buf = (void *) desc;
95a93d
+			  out.d_buf = (void *) &addr;
95a93d
+
95a93d
+			  if (gelf_xlatetom (ebl->elf, &out, &in,
95a93d
+					     elfident[EI_DATA]) == NULL)
95a93d
+			    {
95a93d
+			      printf ("%s\n", elf_errmsg (-1));
95a93d
+			      return;
95a93d
+			    }
95a93d
+			  printf ("%#" PRIx64 "\n", addr);
95a93d
+			}
95a93d
+		      else
95a93d
+			printf (" (garbage datasz: %" PRIx32 ")\n",
95a93d
+				prop.pr_datasz);
95a93d
+		    }
95a93d
+		  else if (prop.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
95a93d
+		    {
95a93d
+		      printf ("NO_COPY_ON_PROTECTION");
95a93d
+		      if (prop.pr_datasz == 0)
95a93d
+			printf ("\n");
95a93d
+		      else
95a93d
+			printf (" (garbage datasz: %" PRIx32 ")\n",
95a93d
+				prop.pr_datasz);
95a93d
+		    }
95a93d
+		  else if (prop.pr_type >= GNU_PROPERTY_LOPROC
95a93d
+		      && prop.pr_type <= GNU_PROPERTY_HIPROC
95a93d
+		      && (ehdr.e_machine == EM_386
95a93d
+			  || ehdr.e_machine == EM_X86_64))
95a93d
+		    {
95a93d
+		      printf ("X86 ");
95a93d
+		      if (prop.pr_type == GNU_PROPERTY_X86_FEATURE_1_AND)
95a93d
+			{
95a93d
+			  printf ("FEATURE_1_AND: ");
95a93d
+
95a93d
+			  if (prop.pr_datasz == 4)
95a93d
+			    {
95a93d
+			      GElf_Word data;
95a93d
+			      in.d_type = ELF_T_WORD;
95a93d
+			      out.d_type = ELF_T_WORD;
95a93d
+			      in.d_size = 4;
95a93d
+			      out.d_size = 4;
95a93d
+			      in.d_buf = (void *) desc;
95a93d
+			      out.d_buf = (void *) &dat;;
95a93d
+
95a93d
+			      if (gelf_xlatetom (ebl->elf, &out, &in,
95a93d
+						 elfident[EI_DATA]) == NULL)
95a93d
+				{
95a93d
+				  printf ("%s\n", elf_errmsg (-1));
95a93d
+				  return;
95a93d
+				}
95a93d
+			      printf ("%08" PRIx32 " ", data);
95a93d
+
95a93d
+			      if ((data & GNU_PROPERTY_X86_FEATURE_1_IBT)
95a93d
+				  != 0)
95a93d
+				{
95a93d
+				  printf ("IBT");
95a93d
+				  data &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
95a93d
+				  if (data != 0)
95a93d
+				    printf (" ");
95a93d
+				}
95a93d
+
95a93d
+			      if ((data & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
95a93d
+				  != 0)
95a93d
+				{
95a93d
+				  printf ("SHSTK");
95a93d
+				  data &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
95a93d
+				  if (data != 0)
95a93d
+				    printf (" ");
95a93d
+				}
95a93d
+
95a93d
+			      if (data != 0)
95a93d
+				printf ("UNKNOWN");
95a93d
+			    }
95a93d
+			  else
95a93d
+			    printf ("<bad datasz: %" PRId32 ">",
95a93d
+				    prop.pr_datasz);
95a93d
+
95a93d
+			  printf ("\n");
95a93d
+			}
95a93d
+		      else
95a93d
+			{
95a93d
+			  printf ("%#" PRIx32, prop.pr_type);
95a93d
+			  if (prop.pr_datasz > 0)
95a93d
+			    {
95a93d
+			      printf (" data: ");
95a93d
+			      size_t i;
95a93d
+			      for (i = 0; i < prop.pr_datasz - 1; i++)
95a93d
+				printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
95a93d
+			      printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
95a93d
+			    }
95a93d
+			}
95a93d
+		    }
95a93d
+		  else
95a93d
+		    {
95a93d
+		      if (prop.pr_type >= GNU_PROPERTY_LOPROC
95a93d
+			  && prop.pr_type <= GNU_PROPERTY_HIPROC)
95a93d
+			printf ("proc_type %#" PRIx32, prop.pr_type);
95a93d
+		      else if (prop.pr_type >= GNU_PROPERTY_LOUSER
95a93d
+			  && prop.pr_type <= GNU_PROPERTY_HIUSER)
95a93d
+			printf ("app_type %#" PRIx32, prop.pr_type);
95a93d
+		      else
95a93d
+			printf ("unknown_type %#" PRIx32, prop.pr_type);
95a93d
+
95a93d
+		      if (prop.pr_datasz > 0)
95a93d
+			{
95a93d
+			  printf (" data: ");
95a93d
+			  size_t i;
95a93d
+			  for (i = 0; i < prop.pr_datasz - 1; i++)
95a93d
+			    printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
95a93d
+			  printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
95a93d
+			}
95a93d
+		    }
95a93d
+		  if (elfclass == ELFCLASS32)
95a93d
+		    {
95a93d
+		      desc += NOTE_ALIGN4 (prop.pr_datasz);
95a93d
+		      descsz -= NOTE_ALIGN4 (prop.pr_datasz);
95a93d
+		    }
95a93d
+		  else
95a93d
+		    {
95a93d
+		      desc += NOTE_ALIGN8 (prop.pr_datasz);
95a93d
+		      descsz -= NOTE_ALIGN8 (prop.pr_datasz);
95a93d
+		    }
95a93d
+		}
95a93d
+	    }
95a93d
+	  break;
95a93d
+
95a93d
 	case NT_GNU_ABI_TAG:
95a93d
 	  if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
95a93d
 	    {
95a93d
diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c
95a93d
index db040d2..af23cae 100644
95a93d
--- a/libebl/eblobjnotetypename.c
95a93d
+++ b/libebl/eblobjnotetypename.c
95a93d
@@ -91,6 +91,7 @@ ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type,
95a93d
 	  KNOWNSTYPE (GNU_HWCAP),
95a93d
 	  KNOWNSTYPE (GNU_BUILD_ID),
95a93d
 	  KNOWNSTYPE (GNU_GOLD_VERSION),
95a93d
+	  KNOWNSTYPE (GNU_PROPERTY_TYPE_0),
95a93d
 	};
95a93d
 
95a93d
       /* Handle standard names.  */
95a93d
diff --git a/libelf/elf32_xlatetom.c b/libelf/elf32_xlatetom.c
95a93d
index 13cd485..3b94cac 100644
95a93d
--- a/libelf/elf32_xlatetom.c
95a93d
+++ b/libelf/elf32_xlatetom.c
95a93d
@@ -60,7 +60,7 @@ elfw2(LIBELFBITS, xlatetom) (Elf_Data *dest, const Elf_Data *src,
95a93d
   /* We shouldn't require integer number of records when processing
95a93d
      notes.  Payload bytes follow the header immediately, it's not an
95a93d
      array of records as is the case otherwise.  */
95a93d
-  if (src->d_type != ELF_T_NHDR
95a93d
+  if (src->d_type != ELF_T_NHDR && src->d_type != ELF_T_NHDR8
95a93d
       && src->d_size % recsize != 0)
95a93d
     {
95a93d
       __libelf_seterrno (ELF_E_INVALID_DATA);
95a93d
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
95a93d
index 711be59..fd412e8 100644
95a93d
--- a/libelf/elf_compress.c
95a93d
+++ b/libelf/elf_compress.c
95a93d
@@ -513,7 +513,8 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
95a93d
 
95a93d
       __libelf_reset_rawdata (scn, scn->zdata_base,
95a93d
 			      scn->zdata_size, scn->zdata_align,
95a93d
-			      __libelf_data_type (elf, sh_type));
95a93d
+			      __libelf_data_type (elf, sh_type,
95a93d
+						  scn->zdata_align));
95a93d
 
95a93d
       return 1;
95a93d
     }
95a93d
diff --git a/libelf/elf_compress_gnu.c b/libelf/elf_compress_gnu.c
95a93d
index dfa7c57..198dc7d 100644
95a93d
--- a/libelf/elf_compress_gnu.c
95a93d
+++ b/libelf/elf_compress_gnu.c
95a93d
@@ -196,7 +196,7 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
95a93d
 	}
95a93d
 
95a93d
       __libelf_reset_rawdata (scn, buf_out, size, sh_addralign,
95a93d
-			      __libelf_data_type (elf, sh_type));
95a93d
+			      __libelf_data_type (elf, sh_type, sh_addralign));
95a93d
 
95a93d
       scn->zdata_base = buf_out;
95a93d
 
95a93d
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
95a93d
index 278dfa8..4f80aaf 100644
95a93d
--- a/libelf/elf_getdata.c
95a93d
+++ b/libelf/elf_getdata.c
95a93d
@@ -65,7 +65,7 @@ static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] =
95a93d
       [SHT_PREINIT_ARRAY] = ELF_T_ADDR,
95a93d
       [SHT_GROUP] = ELF_T_WORD,
95a93d
       [SHT_SYMTAB_SHNDX] = ELF_T_WORD,
95a93d
-      [SHT_NOTE] = ELF_T_NHDR,
95a93d
+      [SHT_NOTE] = ELF_T_NHDR, /* Need alignment to guess ELF_T_NHDR8.  */
95a93d
       [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
95a93d
       [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
95a93d
       [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
95a93d
@@ -106,6 +106,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
95a93d
       [ELF_T_GNUHASH] = __alignof__ (Elf32_Word),			      \
95a93d
       [ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)),			      \
95a93d
       [ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)),			      \
95a93d
+      [ELF_T_NHDR8] = 8 /* Special case for GNU Property note.  */	      \
95a93d
     }
95a93d
     [EV_CURRENT - 1] =
95a93d
     {
95a93d
@@ -118,7 +119,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
95a93d
 
95a93d
 Elf_Type
95a93d
 internal_function
95a93d
-__libelf_data_type (Elf *elf, int sh_type)
95a93d
+__libelf_data_type (Elf *elf, int sh_type, GElf_Xword align)
95a93d
 {
95a93d
   /* Some broken ELF ABI for 64-bit machines use the wrong hash table
95a93d
      entry size.  See elf-knowledge.h for more information.  */
95a93d
@@ -129,7 +130,13 @@ __libelf_data_type (Elf *elf, int sh_type)
95a93d
       return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
95a93d
     }
95a93d
   else
95a93d
-    return shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)];
95a93d
+    {
95a93d
+      Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)];
95a93d
+      /* Special case for GNU Property notes.  */
95a93d
+      if (t == ELF_T_NHDR && align == 8)
95a93d
+	t = ELF_T_NHDR8;
95a93d
+      return t;
95a93d
+    }
95a93d
 }
95a93d
 
95a93d
 /* Convert the data in the current section.  */
95a93d
@@ -272,7 +279,9 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
95a93d
       else
95a93d
 	{
95a93d
 	  Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
95a93d
-	  if (t == ELF_T_VDEF || t == ELF_T_NHDR
95a93d
+	  if (t == ELF_T_NHDR && align == 8)
95a93d
+	    t = ELF_T_NHDR8;
95a93d
+	  if (t == ELF_T_VDEF || t == ELF_T_NHDR || t == ELF_T_NHDR8
95a93d
 	      || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
95a93d
 	    entsize = 1;
95a93d
 	  else
95a93d
@@ -357,7 +366,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
95a93d
   if ((flags & SHF_COMPRESSED) != 0)
95a93d
     scn->rawdata.d.d_type = ELF_T_CHDR;
95a93d
   else
95a93d
-    scn->rawdata.d.d_type = __libelf_data_type (elf, type);
95a93d
+    scn->rawdata.d.d_type = __libelf_data_type (elf, type, align);
95a93d
   scn->rawdata.d.d_off = 0;
95a93d
 
95a93d
   /* Make sure the alignment makes sense.  d_align should be aligned both
95a93d
diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c
95a93d
index 0c50926..d04ec5d 100644
95a93d
--- a/libelf/gelf_fsize.c
95a93d
+++ b/libelf/gelf_fsize.c
95a93d
@@ -64,6 +64,8 @@ const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] =
95a93d
       [ELF_T_VNEED]	= sizeof (ElfW2(LIBELFBITS, Ext_Verneed)),	      \
95a93d
       [ELF_T_VNAUX]	= sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)),	      \
95a93d
       [ELF_T_NHDR]	= sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)),		      \
95a93d
+      /* Note the header size is the same, but padding is different.  */      \
95a93d
+      [ELF_T_NHDR8]	= sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)),		      \
95a93d
       [ELF_T_SYMINFO]	= sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)),	      \
95a93d
       [ELF_T_MOVE]	= sizeof (ElfW2(LIBELFBITS, Ext_Move)),		      \
95a93d
       [ELF_T_LIB]	= sizeof (ElfW2(LIBELFBITS, Ext_Lib)),		      \
95a93d
diff --git a/libelf/gelf_getnote.c b/libelf/gelf_getnote.c
95a93d
index c75edda..6d33b35 100644
95a93d
--- a/libelf/gelf_getnote.c
95a93d
+++ b/libelf/gelf_getnote.c
95a93d
@@ -1,5 +1,5 @@
95a93d
 /* Get note information at the supplied offset.
95a93d
-   Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
95a93d
+   Copyright (C) 2007, 2014, 2015, 2018 Red Hat, Inc.
95a93d
    This file is part of elfutils.
95a93d
 
95a93d
    This file is free software; you can redistribute it and/or modify
95a93d
@@ -43,7 +43,7 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
95a93d
   if (data == NULL)
95a93d
     return 0;
95a93d
 
95a93d
-  if (unlikely (data->d_type != ELF_T_NHDR))
95a93d
+  if (unlikely (data->d_type != ELF_T_NHDR && data->d_type != ELF_T_NHDR8))
95a93d
     {
95a93d
       __libelf_seterrno (ELF_E_INVALID_HANDLE);
95a93d
       return 0;
95a93d
@@ -69,27 +69,42 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
95a93d
       const GElf_Nhdr *n = data->d_buf + offset;
95a93d
       offset += sizeof *n;
95a93d
 
95a93d
-      /* Include padding.  Check below for overflow.  */
95a93d
-      GElf_Word namesz = NOTE_ALIGN (n->n_namesz);
95a93d
-      GElf_Word descsz = NOTE_ALIGN (n->n_descsz);
95a93d
-
95a93d
-      if (unlikely (offset > data->d_size
95a93d
-		    || data->d_size - offset < namesz
95a93d
-		    || (namesz == 0 && n->n_namesz != 0)))
95a93d
+      if (offset > data->d_size)
95a93d
 	offset = 0;
95a93d
       else
95a93d
 	{
95a93d
+	  /* This is slightly tricky, offset is guaranteed to be 4
95a93d
+	     byte aligned, which is what we need for the name_offset.
95a93d
+	     And normally desc_offset is also 4 byte aligned, but not
95a93d
+	     for GNU Property notes, then it should be 8.  So align
95a93d
+	     the offset, after adding the namesz, and include padding
95a93d
+	     in descsz to get to the end.  */
95a93d
 	  *name_offset = offset;
95a93d
-	  offset += namesz;
95a93d
-	  if (unlikely (offset > data->d_size
95a93d
-			|| data->d_size - offset < descsz
95a93d
-			|| (descsz == 0 && n->n_descsz != 0)))
95a93d
+	  offset += n->n_namesz;
95a93d
+	  if (offset > data->d_size)
95a93d
 	    offset = 0;
95a93d
 	  else
95a93d
 	    {
95a93d
-	      *desc_offset = offset;
95a93d
-	      offset += descsz;
95a93d
-	      *result = *n;
95a93d
+	      /* Include padding.  Check below for overflow.  */
95a93d
+	      GElf_Word descsz = (data->d_type == ELF_T_NHDR8
95a93d
+				  ? NOTE_ALIGN8 (n->n_descsz)
95a93d
+				  : NOTE_ALIGN4 (n->n_descsz));
95a93d
+
95a93d
+	      if (data->d_type == ELF_T_NHDR8)
95a93d
+		offset = NOTE_ALIGN8 (offset);
95a93d
+	      else
95a93d
+		offset = NOTE_ALIGN4 (offset);
95a93d
+
95a93d
+	      if (unlikely (offset > data->d_size
95a93d
+			    || data->d_size - offset < descsz
95a93d
+			    || (descsz == 0 && n->n_descsz != 0)))
95a93d
+		offset = 0;
95a93d
+	      else
95a93d
+		{
95a93d
+		  *desc_offset = offset;
95a93d
+		  offset += descsz;
95a93d
+		  *result = *n;
95a93d
+		}
95a93d
 	    }
95a93d
 	}
95a93d
     }
95a93d
diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c
95a93d
index 479f143..b5d6ef3 100644
95a93d
--- a/libelf/gelf_xlate.c
95a93d
+++ b/libelf/gelf_xlate.c
95a93d
@@ -195,7 +195,8 @@ const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
95a93d
 	[ELF_T_VDAUX]	= elf_cvt_Verdef,				      \
95a93d
 	[ELF_T_VNEED]	= elf_cvt_Verneed,				      \
95a93d
 	[ELF_T_VNAUX]	= elf_cvt_Verneed,				      \
95a93d
-	[ELF_T_NHDR]	= elf_cvt_note,					      \
95a93d
+	[ELF_T_NHDR]	= elf_cvt_note4,				      \
95a93d
+	[ELF_T_NHDR8]	= elf_cvt_note8,				      \
95a93d
 	[ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo),			      \
95a93d
 	[ELF_T_MOVE]	= ElfW2(Bits, cvt_Move),			      \
95a93d
 	[ELF_T_LIB]	= ElfW2(Bits, cvt_Lib),				      \
95a93d
diff --git a/libelf/libelf.h b/libelf/libelf.h
95a93d
index d11358c..1ff11c9 100644
95a93d
--- a/libelf/libelf.h
95a93d
+++ b/libelf/libelf.h
95a93d
@@ -117,6 +117,8 @@ typedef enum
95a93d
   ELF_T_GNUHASH,		/* GNU-style hash section.  */
95a93d
   ELF_T_AUXV,			/* Elf32_auxv_t, Elf64_auxv_t, ... */
95a93d
   ELF_T_CHDR,			/* Compressed, Elf32_Chdr, Elf64_Chdr, ... */
95a93d
+  ELF_T_NHDR8,			/* Special GNU Properties note.  Same as Nhdr,
95a93d
+				   except padding.  */
95a93d
   /* Keep this the last entry.  */
95a93d
   ELF_T_NUM
95a93d
 } Elf_Type;
95a93d
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
95a93d
index ed216c8..fa6d55d 100644
95a93d
--- a/libelf/libelfP.h
95a93d
+++ b/libelf/libelfP.h
95a93d
@@ -452,7 +452,8 @@ extern const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_
95a93d
 /* Given an Elf handle and a section type returns the Elf_Data d_type.
95a93d
    Should not be called when SHF_COMPRESSED is set, the d_type should
95a93d
    be ELF_T_BYTE.  */
95a93d
-extern Elf_Type __libelf_data_type (Elf *elf, int sh_type) internal_function;
95a93d
+extern Elf_Type __libelf_data_type (Elf *elf, int sh_type, GElf_Xword align)
95a93d
+  internal_function;
95a93d
 
95a93d
 /* The libelf API does not have such a function but it is still useful.
95a93d
    Get the memory size for the given type.
95a93d
@@ -624,8 +625,13 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size,
95a93d
       }									      \
95a93d
   } while (0)
95a93d
 
95a93d
-/* Align offset to 4 bytes as needed for note name and descriptor data.  */
95a93d
-#define NOTE_ALIGN(n)	(((n) + 3) & -4U)
95a93d
+/* Align offset to 4 bytes as needed for note name and descriptor data.
95a93d
+   This is almost always used, except for GNU Property notes, which use
95a93d
+   8 byte padding...  */
95a93d
+#define NOTE_ALIGN4(n)	(((n) + 3) & -4U)
95a93d
+
95a93d
+/* Special note padding rule for GNU Property notes.  */
95a93d
+#define NOTE_ALIGN8(n)	(((n) + 7) & -8U)
95a93d
 
95a93d
 /* Convenience macro.  */
95a93d
 #define INVALID_NDX(ndx, type, data) \
95a93d
diff --git a/libelf/note_xlate.h b/libelf/note_xlate.h
95a93d
index 62c6f63..9bdc3e2 100644
95a93d
--- a/libelf/note_xlate.h
95a93d
+++ b/libelf/note_xlate.h
95a93d
@@ -1,5 +1,5 @@
95a93d
 /* Conversion functions for notes.
95a93d
-   Copyright (C) 2007, 2009, 2014 Red Hat, Inc.
95a93d
+   Copyright (C) 2007, 2009, 2014, 2018 Red Hat, Inc.
95a93d
    This file is part of elfutils.
95a93d
 
95a93d
    This file is free software; you can redistribute it and/or modify
95a93d
@@ -27,38 +27,60 @@
95a93d
    not, see <http://www.gnu.org/licenses/>.  */
95a93d
 
95a93d
 static void
95a93d
-elf_cvt_note (void *dest, const void *src, size_t len, int encode)
95a93d
+elf_cvt_note (void *dest, const void *src, size_t len, int encode,
95a93d
+	      bool nhdr8)
95a93d
 {
95a93d
+  /* Note that the header is always the same size, but the padding
95a93d
+     differs for GNU Property notes.  */
95a93d
   assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
95a93d
 
95a93d
   while (len >= sizeof (Elf32_Nhdr))
95a93d
     {
95a93d
+      /* Convert the header.  */
95a93d
       (1 ? Elf32_cvt_Nhdr : Elf64_cvt_Nhdr) (dest, src, sizeof (Elf32_Nhdr),
95a93d
 					     encode);
95a93d
       const Elf32_Nhdr *n = encode ? src : dest;
95a93d
-      Elf32_Word namesz = NOTE_ALIGN (n->n_namesz);
95a93d
-      Elf32_Word descsz = NOTE_ALIGN (n->n_descsz);
95a93d
 
95a93d
-      len -= sizeof *n;
95a93d
-      src += sizeof *n;
95a93d
-      dest += sizeof *n;
95a93d
+      size_t note_len = sizeof *n;
95a93d
 
95a93d
-      if (namesz > len)
95a93d
+      /* desc needs to be aligned.  */
95a93d
+      note_len += n->n_namesz;
95a93d
+      note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len);
95a93d
+      if (note_len > len || note_len < 8)
95a93d
 	break;
95a93d
-      len -= namesz;
95a93d
-      if (descsz > len)
95a93d
+
95a93d
+      /* data as a whole needs to be aligned.  */
95a93d
+      note_len += n->n_descsz;
95a93d
+      note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len);
95a93d
+      if (note_len > len || note_len < 8)
95a93d
 	break;
95a93d
-      len -= descsz;
95a93d
 
95a93d
+      /* Copy or skip the note data.  */
95a93d
+      size_t note_data_len = note_len - sizeof *n;
95a93d
+      src += sizeof *n;
95a93d
+      dest += sizeof *n;
95a93d
       if (src != dest)
95a93d
-	memcpy (dest, src, namesz + descsz);
95a93d
+	memcpy (dest, src, note_data_len);
95a93d
 
95a93d
-      src += namesz + descsz;
95a93d
-      dest += namesz + descsz;
95a93d
+      src += note_data_len;
95a93d
+      dest += note_data_len;
95a93d
+      len -= note_len;
95a93d
     }
95a93d
 
95a93d
-    /* Copy opver any leftover data unconcerted.  Probably part of
95a93d
+    /* Copy over any leftover data unconverted.  Probably part of
95a93d
        truncated name/desc data.  */
95a93d
     if (unlikely (len > 0) && src != dest)
95a93d
       memcpy (dest, src, len);
95a93d
 }
95a93d
+
95a93d
+static void
95a93d
+elf_cvt_note4 (void *dest, const void *src, size_t len, int encode)
95a93d
+{
95a93d
+  elf_cvt_note (dest, src, len, encode, false);
95a93d
+}
95a93d
+
95a93d
+static void
95a93d
+elf_cvt_note8 (void *dest, const void *src, size_t len, int encode)
95a93d
+{
95a93d
+  elf_cvt_note (dest, src, len, encode, true);
95a93d
+}
95a93d
diff --git a/src/elflint.c b/src/elflint.c
95a93d
index 3d44595..fa3af4c 100644
95a93d
--- a/src/elflint.c
95a93d
+++ b/src/elflint.c
95a93d
@@ -4331,6 +4331,7 @@ section [%2d] '%s': unknown core file note type %" PRIu32
95a93d
 	  case NT_GNU_HWCAP:
95a93d
 	  case NT_GNU_BUILD_ID:
95a93d
 	  case NT_GNU_GOLD_VERSION:
95a93d
+	  case NT_GNU_PROPERTY_TYPE_0:
95a93d
 	    break;
95a93d
 
95a93d
 	  case 0:
95a93d
@@ -4376,7 +4377,8 @@ phdr[%d]: no note entries defined for the type of file\n"),
95a93d
   GElf_Off notes_size = 0;
95a93d
   Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
95a93d
 					 phdr->p_offset, phdr->p_filesz,
95a93d
-					 ELF_T_NHDR);
95a93d
+					 (phdr->p_align == 8
95a93d
+					  ? ELF_T_NHDR8 : ELF_T_NHDR));
95a93d
   if (data != NULL && data->d_buf != NULL)
95a93d
     notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
95a93d
 
95a93d
diff --git a/src/readelf.c b/src/readelf.c
95a93d
index 72ae04e..ccd07eb 100644
95a93d
--- a/src/readelf.c
95a93d
+++ b/src/readelf.c
95a93d
@@ -12300,7 +12300,8 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
95a93d
       handle_notes_data (ebl, ehdr, phdr->p_offset,
95a93d
 			 elf_getdata_rawchunk (ebl->elf,
95a93d
 					       phdr->p_offset, phdr->p_filesz,
95a93d
-					       ELF_T_NHDR));
95a93d
+					       (phdr->p_align == 8
95a93d
+						? ELF_T_NHDR8 : ELF_T_NHDR)));
95a93d
     }
95a93d
 }
95a93d