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