diff options
author | Mark Wielaard <mark@klomp.org> | 2018-10-15 23:35:47 +0200 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2018-10-29 00:57:57 +0100 |
commit | 5199e15870e05e5b0b9f98c20fc9b5427aa6dd6a (patch) | |
tree | 300abbc40ba85162eabf061393f9f5c0cff9b9b2 /libebl | |
parent | b75ff1bbd060404565fa28d72441a9b02f331bae (diff) | |
download | elfutils-5199e15870e05e5b0b9f98c20fc9b5427aa6dd6a.tar.gz |
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 <mark@klomp.org>
Diffstat (limited to 'libebl')
-rw-r--r-- | libebl/ChangeLog | 6 | ||||
-rw-r--r-- | libebl/eblobjnote.c | 185 | ||||
-rw-r--r-- | libebl/eblobjnotetypename.c | 1 |
3 files changed, 191 insertions, 1 deletions
diff --git a/libebl/ChangeLog b/libebl/ChangeLog index aec848b9..120c84c0 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,9 @@ +2018-10-18 Mark Wielaard <mark@klomp.org> + + * eblobjnote.c (ebl_object_note): Handle NT_GNU_PROPERTY_TYPE_0. + * eblobjnotetypename.c (ebl_object_note_type_name): Add + GNU_PROPERTY_TYPE_0. + 2018-10-02 Andreas Schwab <schwab@suse.de> * ebl-hooks.h (EBLHOOK(reloc_simple_type)): Add third parameter. diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c index ca4f155d..57e9f52f 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 <drepper@redhat.com>, 2002. @@ -37,6 +37,8 @@ #include <string.h> #include <libeblP.h> +#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 ("<bad datasz: %" PRId32 ">", + 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 db040d29..af23caea 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. */ |