Add support for note GNU_PROPERTY_X86_FEATURE_1_AND (#388)
authorMarco Bonelli <marco@mebeim.net>
Wed, 15 Dec 2021 19:25:34 +0000 (20:25 +0100)
committerGitHub <noreply@github.com>
Wed, 15 Dec 2021 19:25:34 +0000 (11:25 -0800)
- 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
elftools/elf/enums.py
elftools/elf/structs.py
scripts/readelf.py
test/testfiles_for_readelf/note_gnu_property.S
test/testfiles_for_readelf/note_gnu_property.elf
test/testfiles_for_readelf/note_gnu_property.o.elf

index d15cbe1e982e1ba19400f4f253cc7bd29a01bd0e..53c5b16d88efd1de3707c41e54b37b84f4889a41 100644 (file)
@@ -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 = ' <corrupt length: 0x%x>' % sz
             else:
                 prop_desc = 'no copy on protected'
+        elif t == 'GNU_PROPERTY_X86_FEATURE_1_AND':
+            if sz != 4:
+                prop_desc = ' <corrupt length: 0x%x>' % 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 = '<processor-specific type 0x%x data: %s >' % (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
index 201ad96433af7761c56502bbdf7995b63286e64e..43e5302d72d7406fdd4c192687411c1dc2ff5da7 100644 (file)
@@ -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,
index f25cf782b53f21d613ebab27328a1e90df2a3f2f..f9bf6860ad966c4d1c3a5ffd56ca525f7c552228 100644 (file)
@@ -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)
             ),
index 2ddd02ba26871f4a0e2341aa6be07f01160b5aa8..1e3213b6ba1c7f7a736f90095ce8f8dd04ed05c4 100755 (executable)
@@ -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),
index 0b11b6bcdf196f7e1a5dd9ee78ce9865e21bea13..20a845b3dc68c9f8f2c2e789154226a009039d22 100644 (file)
@@ -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
 
 // 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:
index c97e060a501e20aa668636c23825fc47067ab8f2..408efee74f80572fb92e50a0df9227e11a4ff34c 100755 (executable)
Binary files a/test/testfiles_for_readelf/note_gnu_property.elf and b/test/testfiles_for_readelf/note_gnu_property.elf differ
index 2f6f6b8e685d46aca26f8052f5aad92d960b13d8..f7f3a63b5371d42ca6db66014272c216f8dce068 100644 (file)
Binary files a/test/testfiles_for_readelf/note_gnu_property.o.elf and b/test/testfiles_for_readelf/note_gnu_property.o.elf differ