From 8f7a0becaface09435c4374947548b7851e3d1a2 Mon Sep 17 00:00:00 2001 From: Marco Bonelli Date: Wed, 15 Dec 2021 20:25:34 +0100 Subject: [PATCH] Add support for note GNU_PROPERTY_X86_FEATURE_1_AND (#388) - Implement support for GNU property note type GNU_PROPERTY_X86_FEATURE_1_AND (which is a feature bitmask) and its relative flags. - Fix off-by-one in "Data size" column alignment for readelf.py note sections dump. References: - https://gitlab.com/x86-psABIs/x86-64-ABI --- elftools/elf/descriptions.py | 24 +++++++++++ elftools/elf/enums.py | 9 +++++ elftools/elf/structs.py | 14 +++++-- scripts/readelf.py | 2 +- .../testfiles_for_readelf/note_gnu_property.S | 38 ++++++++++++------ .../note_gnu_property.elf | Bin 4792 -> 4792 bytes .../note_gnu_property.o.elf | Bin 928 -> 944 bytes 7 files changed, 69 insertions(+), 18 deletions(-) diff --git a/elftools/elf/descriptions.py b/elftools/elf/descriptions.py index d15cbe1..53c5b16 100644 --- a/elftools/elf/descriptions.py +++ b/elftools/elf/descriptions.py @@ -252,6 +252,13 @@ def describe_attr_tag_arm(tag, val, extra): return _DESCR_ATTR_TAG_ARM[tag] + d_entry[val] +def describe_note_gnu_property_x86_feature_1(value): + descs = [] + for mask, desc in _DESCR_NOTE_GNU_PROPERTY_X86_FEATURE_1_FLAGS: + if value & mask: + descs.append(desc) + return 'x86 feature: ' + ', '.join(descs) + def describe_note_gnu_properties(properties): descriptions = [] for prop in properties: @@ -266,6 +273,11 @@ def describe_note_gnu_properties(properties): prop_desc = ' ' % sz else: prop_desc = 'no copy on protected' + elif t == 'GNU_PROPERTY_X86_FEATURE_1_AND': + if sz != 4: + prop_desc = ' ' % sz + else: + prop_desc = describe_note_gnu_property_x86_feature_1(d) elif _DESCR_NOTE_GNU_PROPERTY_TYPE_LOPROC <= t <= _DESCR_NOTE_GNU_PROPERTY_TYPE_HIPROC: prop_desc = '' % (t, bytes2hex(d, sep=' ')) elif _DESCR_NOTE_GNU_PROPERTY_TYPE_LOUSER <= t <= _DESCR_NOTE_GNU_PROPERTY_TYPE_HIUSER: @@ -571,6 +583,7 @@ _DESCR_NOTE_ABI_TAG_OS = dict( ELF_NOTE_OS_SYLLABLE='Syllable', ) + # Values in GNU .note.gnu.property notes (n_type=='NT_GNU_PROPERTY_TYPE_0') have # different formats which need to be parsed/described differently _DESCR_NOTE_GNU_PROPERTY_TYPE_LOPROC=0xc0000000 @@ -578,6 +591,17 @@ _DESCR_NOTE_GNU_PROPERTY_TYPE_HIPROC=0xdfffffff _DESCR_NOTE_GNU_PROPERTY_TYPE_LOUSER=0xe0000000 _DESCR_NOTE_GNU_PROPERTY_TYPE_HIUSER=0xffffffff + +# Bit masks for GNU_PROPERTY_X86_FEATURE_1_xxx flags in the form +# (mask, flag_description) in the desired output order +_DESCR_NOTE_GNU_PROPERTY_X86_FEATURE_1_FLAGS = ( + (1, 'IBT'), + (2, 'SHSTK'), + (4, 'LAM_U48'), + (8, 'LAM_U57'), +) + + def _reverse_dict(d, low_priority=()): """ This is a tiny helper function to "reverse" the keys/values of a dictionary diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py index 201ad96..43e5302 100644 --- a/elftools/elf/enums.py +++ b/elftools/elf/enums.py @@ -870,9 +870,18 @@ ENUM_NOTE_ABI_TAG_OS = dict( ENUM_NOTE_GNU_PROPERTY_TYPE = dict( GNU_PROPERTY_STACK_SIZE=1, GNU_PROPERTY_NO_COPY_ON_PROTECTED=2, + GNU_PROPERTY_X86_FEATURE_1_AND=0xc0000002, _default_=Pass, ) +ENUM_GNU_PROPERTY_X86_FEATURE_1_FLAGS = dict( + GNU_PROPERTY_X86_FEATURE_1_IBT=1, + GNU_PROPERTY_X86_FEATURE_1_SHSTK=2, + GNU_PROPERTY_X86_FEATURE_1_LAM_U48=4, + GNU_PROPERTY_X86_FEATURE_1_LAM_U57=8, + _default_=Pass +) + ENUM_RELOC_TYPE_ARM = dict( R_ARM_NONE=0, R_ARM_PC24=1, diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py index f25cf78..f9bf686 100644 --- a/elftools/elf/structs.py +++ b/elftools/elf/structs.py @@ -383,14 +383,20 @@ class ELFStructs(object): return roundup(ctx.pr_datasz, 2) - ctx.pr_datasz return roundup(ctx.pr_datasz, 3) - ctx.pr_datasz + def classify_pr_data(ctx): + if type(ctx.pr_type) is not str: + return None + if ctx.pr_type.startswith('GNU_PROPERTY_X86_'): + return ('GNU_PROPERTY_X86_*', 4, 0) + return (ctx.pr_type, ctx.pr_datasz, self.elfclass) + self.Elf_Prop = Struct('Elf_Prop', Enum(self.Elf_word('pr_type'), **ENUM_NOTE_GNU_PROPERTY_TYPE), self.Elf_word('pr_datasz'), - Switch('pr_data', - lambda ctx: (ctx.pr_type, ctx.pr_datasz, self.elfclass), - { + Switch('pr_data', classify_pr_data, { ('GNU_PROPERTY_STACK_SIZE', 4, 32): self.Elf_word('pr_data'), - ('GNU_PROPERTY_STACK_SIZE', 8, 64): self.Elf_word64('pr_data') + ('GNU_PROPERTY_STACK_SIZE', 8, 64): self.Elf_word64('pr_data'), + ('GNU_PROPERTY_X86_*', 4, 0): self.Elf_word('pr_data'), }, default=Field('pr_data', lambda ctx: ctx.pr_datasz) ), diff --git a/scripts/readelf.py b/scripts/readelf.py index 2ddd02b..1e3213b 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -505,7 +505,7 @@ class ReadElf(object): for note in section.iter_notes(): self._emitline("\nDisplaying notes found in: {}".format( section.name)) - self._emitline(' Owner Data size Description') + self._emitline(' Owner Data size Description') self._emitline(' %s %s\t%s' % ( note['n_name'].ljust(20), self._format_hex(note['n_descsz'], fieldsize=8), diff --git a/test/testfiles_for_readelf/note_gnu_property.S b/test/testfiles_for_readelf/note_gnu_property.S index 0b11b6b..20a845b 100644 --- a/test/testfiles_for_readelf/note_gnu_property.S +++ b/test/testfiles_for_readelf/note_gnu_property.S @@ -7,7 +7,6 @@ * ELF executable (to also have a PT_GNU_PROPERTY program header): * gcc -DEXE -c note_gnu_property.S -o /tmp/x.o * ld /tmp/x.o -o note_gnu_property.elf - * strip */ // https://github.com/hjl-tools/linux-abi/wiki/linux-abi-draft.pdf @@ -21,13 +20,23 @@ // Unknown property types for testing purposes #define GNU_PROPERTY_TEST_UNKNOWN 0x12345678 -#define GNU_PROPERTY_TEST_UNKNOWN_PROC 0xc1234567 -#define GNU_PROPERTY_TEST_UNKNOWN_USER 0xe1234567 +#define GNU_PROPERTY_TEST_UNKNOWN_PROC (GNU_PROPERTY_LOPROC + 0x1234567) +#define GNU_PROPERTY_TEST_UNKNOWN_USER (GNU_PROPERTY_LOUSER + 0x1234567) +// https://gitlab.com/x86-psABIs/x86-64-ABI/ // https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI -#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002 -#define GNU_PROPERTY_X86_FEATURE_1_IBT 0x00000001 -#define GNU_PROPERTY_X86_FEATURE_1_SHSTK 0x00000002 +#define GNU_PROPERTY_X86_UINT32_AND_LO 0xc0000002 +#define GNU_PROPERTY_X86_UINT32_AND_HI 0xc0007fff +#define GNU_PROPERTY_X86_UINT32_OR_LO 0xc0008000 +#define GNU_PROPERTY_X86_UINT32_OR_HI 0xc000ffff +#define GNU_PROPERTY_X86_UINT32_OR_AND_LO 0xc0010000 +#define GNU_PROPERTY_X86_UINT32_OR_AND_HI 0xc0017fff + +#define GNU_PROPERTY_X86_FEATURE_1_AND (GNU_PROPERTY_X86_UINT32_AND_LO + 0) +#define GNU_PROPERTY_X86_FEATURE_1_IBT (1U << 0) +#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (1U << 1) +#define GNU_PROPERTY_X86_FEATURE_1_LAM_U48 (1U << 2) +#define GNU_PROPERTY_X86_FEATURE_1_LAM_U57 (1U << 3) #ifdef __x86_64__ #define ALIGN .p2align 3 @@ -80,12 +89,15 @@ _start: ALIGN #endif -/* TODO: add support for these later... -6: .long GNU_PROPERTY_X86_FEATURE_1_AND // pr_type. - .long 8f - 7f // pr_datasz -7: - .long GNU_PROPERTY_X86_FEATURE_1_IBT|GNU_PROPERTY_X86_FEATURE_1_SHSTK -8: +11: .long GNU_PROPERTY_X86_FEATURE_1_AND // pr_type. + .long 13f - 12f // pr_datasz +12: + // Not sure if LAM_U48 and LAM_U57 make sense together, readelf does not + // seem to complain and outputs both. + .long GNU_PROPERTY_X86_FEATURE_1_IBT \ + | GNU_PROPERTY_X86_FEATURE_1_SHSTK \ + | GNU_PROPERTY_X86_FEATURE_1_LAM_U48 \ + | GNU_PROPERTY_X86_FEATURE_1_LAM_U57 +13: ALIGN -*/ end: diff --git a/test/testfiles_for_readelf/note_gnu_property.elf b/test/testfiles_for_readelf/note_gnu_property.elf index c97e060a501e20aa668636c23825fc47067ab8f2..408efee74f80572fb92e50a0df9227e11a4ff34c 100755 GIT binary patch delta 84 zcmdm?xMjO0>+5Vg#zk~j24?`3d%DA0G~w=8vpn#zm;6Mds6ZjzaJC516zvnAtnM#hB67n#f%S4`$)wr32O?8$7; O8N