]> sourceware.org Git - annobin.git/commitdiff
Add recording of control-flow protection options
authorNick Clifton <nickc@redhat.com>
Wed, 31 Jan 2018 10:51:52 +0000 (10:51 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 31 Jan 2018 10:51:52 +0000 (10:51 +0000)
12 files changed:
doc/annobin.info
doc/annobin.texi
doc/annotation.proposal.txt
plugin/aarch64.annobin.cc
plugin/annobin.cc
plugin/annobin.h
plugin/powerpc.annobin.cc
plugin/x86_64.annobin.cc
scripts/hardened.sh
tests/Makefile.am
tests/hardening-fail-test
tests/hardening-test

index dfda3bc7b28e55ff4d4658d2e3a2ed9aa3ca78a8..b3e9d24be920b7ee75658c82883316cef8cd0b52 100644 (file)
@@ -26,7 +26,7 @@ Annotating Binaries: How Was Your Program Built ?
 This manual describes the ANNOBIN plugin, and how you can use it to
 determine what security features were used when building your binary.
 
-   This manual is for 'annobin' (Annobin) version 3.1.
+   This manual is for 'annobin' (Annobin) version 3.2.
 
    This document is distributed under the terms of the GNU Free
 Documentation License version 1.3.  A copy of the license is included in
@@ -195,6 +195,8 @@ below.
 
 * The Version Encoding::  Encoding Versions
 * The GOW Encoding::      Encoding Optimization and Debugging Levels
+* The CF Encoding::       Encoding Control Flow Protection
+* The CET Encoding::      Encoding Control Flow Enforcement Technology
 
    The 'annobin' package includes some example scripts that demonstrate
 how the binary information can be used.  The scripts are:
@@ -220,8 +222,10 @@ how the binary information can be used.  The scripts are:
      Reports on the hardening status of the specified file(s).  In
      particular it checks that the whole file was compiled with '-O2' or
      higher and the '-fstack-protector-strong', '-D_FORTIFY_SOURCE=2',
-     '-Wl,-z,now', '-Wl,-z,relro', '-fPIE', '-Wp,-D_GLIBCXX_ASSERTIONS'
-     and '-fstack-clash-protection' options.
+     '-Wl,-z,now', '-Wl,-z,relro', '-fPIE', '-Wp,-D_GLIBCXX_ASSERTIONS',
+     '-fstack-clash-protection' '-fcf-protection=full' and '-mcet'
+     options.  Tests of each of these options can be individually
+     toggled on and off using command line options to the script.
 
 \1f
 File: annobin.info,  Node: The Version Encoding,  Next: The GOW Encoding,  Up: Checking
@@ -234,7 +238,7 @@ used and the version of the tool used to generate the notes.  Typically
 these will both be 3.
 
 \1f
-File: annobin.info,  Node: The GOW Encoding,  Prev: The Version Encoding,  Up: Checking
+File: annobin.info,  Node: The GOW Encoding,  Next: The CF Encoding,  Prev: The Version Encoding,  Up: Checking
 
 3.2 Encoding Optimization and Debugging Levels
 ==============================================
@@ -278,6 +282,61 @@ stored as a bit field with the bits having the following meanings:
    The other bits are not currently used and should be set to zero so
 they can be used in future extensions to the specification.
 
+\1f
+File: annobin.info,  Node: The CF Encoding,  Next: The CET Encoding,  Prev: The GOW Encoding,  Up: Checking
+
+3.3 Encoding Control Flow Protection
+====================================
+
+Records the setting of the '-cf-protection' option.  This is a bit mask
+using the following bits, based upon the definition of the 'enum
+cf_protection_level' from gcc's 'flag-types.h' header file:
+
+'bit 0'
+     Branches are protected.  (ie '-fcf-protection=branch').
+
+'bit 1'
+     Returns are protected.  (ie '-fcf-protection=return').
+
+'bit 2'
+     If set, this indicates that the other bits were explicitly set by
+     an option on the gcc command line.  Otherwise those bits were
+     implicitly set by either other options or the backend concerned.
+
+   If both bits 0 and 1 are set then this implies the
+'-fcf-protection=full' option, and if neither are set then this implies
+the '-fcf-protection=none' option.
+
+   Note - in order to avoid storing a value of 0 in the note (which can
+be confused with a NUL-byte to indicate the end of a string), the value
+stored is biased by 1.
+
+\1f
+File: annobin.info,  Node: The CET Encoding,  Prev: The CF Encoding,  Up: Checking
+
+3.4 Encoding Control Flow Enforcement Technology
+================================================
+
+Records the setting of the Control Flow Enforcement Technology options.
+(These are specific to the x86_64 port of gcc).  The value is a sequence
+of bytes that indicate various different flags:
+
+'byte 0'
+     The setting of the '-mcet' option.  This is either 1 (not set) or 2
+     (set).
+
+'byte 1'
+     The setting of the '-mcet-switch' option.  This is either 1 (not
+     set) or 2 (set).
+
+'byte 2'
+     The setting of the '-mibt' option.  This is either 1 (not set) or 2
+     (set).
+
+'byte 3'
+     The setting of the '-mshstk' option.  This is either 1 (not set) or
+     2 (set).
+
 \1f
 File: annobin.info,  Node: GNU Free Documentation License,  Prev: Checking,  Up: Top
 
@@ -767,8 +826,10 @@ Node: Top\7f706
 Node: Introduction\7f1543
 Node: Invocation\7f3645
 Node: Checking\7f6476
-Node: The Version Encoding\7f9958
-Node: The GOW Encoding\7f10303
-Node: GNU Free Documentation License\7f11730
+Node: The Version Encoding\7f10243
+Node: The GOW Encoding\7f10588
+Node: The CF Encoding\7f12039
+Node: The CET Encoding\7f13109
+Node: GNU Free Documentation License\7f13877
 \1f
 End Tag Table
index 99b283bdbb7f4ed48b5e45adf83cee67f3447c6d..17b5b3e113471a5bc7d8f91b648402951e12f200 100644 (file)
@@ -5,7 +5,7 @@
 @setchapternewpage odd
 
 @c man begin INCLUDE
-@set VERSION 3.1
+@set VERSION 3.2
 @set VERSION_PACKAGE (Annobin) 
 @set UPDATED January 2018
 @c man end
@@ -243,6 +243,8 @@ explained below.
 @menu
 * The Version Encoding::  Encoding Versions
 * The GOW Encoding::      Encoding Optimization and Debugging Levels
+* The CF Encoding::       Encoding Control Flow Protection
+* The CET Encoding::      Encoding Control Flow Enforcement Technology
 @end menu
 
 The @command{annobin} package includes some example scripts that
@@ -272,9 +274,11 @@ particular it checks that the whole file was compiled with
 @option{-O2} or higher and the @option{-fstack-protector-strong},
 @option{-D_FORTIFY_SOURCE=2}, @option{-Wl,-z,now},
 @option{-Wl,-z,relro}, @option{-fPIE},
-@option{-Wp,-D_GLIBCXX_ASSERTIONS} and
-@option{-fstack-clash-protection} options.
-
+@option{-Wp,-D_GLIBCXX_ASSERTIONS}, @option{-fstack-clash-protection}
+@option{-fcf-protection=full} and @option{-mcet}
+options.
+Tests of each of these options can be individually toggled on and off
+using command line options to the script.
 @end table
 
 
@@ -284,6 +288,7 @@ The @code{version} note encodes the version of the Watermark
 specification used and the version of the tool used to generate the
 notes.  Typically these will both be 3.
 
+
 @node The GOW Encoding
 @section Encoding Optimization and Debugging Levels
 
@@ -332,6 +337,61 @@ enabled.
 The other bits are not currently used and should be set to zero so
 they can be used in future extensions to the specification.
 
+
+@node The CF Encoding
+@section Encoding Control Flow Protection
+Records the setting of the @option{-cf-protection} option.  This is a
+bit mask using the following bits, based upon the definition of the
+@code{enum cf_protection_level} from gcc's @code{flag-types.h} header
+file:
+
+@table @code
+@item bit 0
+Branches are protected.  (ie @option{-fcf-protection=branch}).
+
+@item bit 1
+Returns are protected.  (ie @option{-fcf-protection=return}).
+
+@item bit 2
+If set, this indicates that the other bits were explicitly set by an
+option on the gcc command line.  Otherwise those bits were implicitly
+set by either other options or the backend concerned.
+@end table
+
+If both bits 0 and 1 are set then this implies the
+@option{-fcf-protection=full} option, and if neither are set then this
+implies the @option{-fcf-protection=none} option.
+
+Note - in order to avoid storing a value of 0 in the note (which can
+be confused with a NUL-byte to indicate the end of a string), the
+value stored is biased by 1.
+
+
+@node The CET Encoding
+@section Encoding Control Flow Enforcement Technology
+Records the setting of the Control Flow Enforcement Technology
+options.  (These are specific to the x86_64 port of gcc).  The value
+is a sequence of bytes that indicate various different flags:
+
+@table @code
+@item byte 0
+The setting of the @option{-mcet} option.  This is either 1 (not set)
+or 2 (set).
+
+@item byte 1
+The setting of the @option{-mcet-switch} option.  This is either 1
+(not set) or 2 (set).
+
+@item byte 2
+The setting of the @option{-mibt} option.  This is either 1 (not set)
+or 2 (set).
+
+@item byte 3
+The setting of the @option{-mshstk} option.  This is either 1 (not
+set) or 2 (set).
+@end table
+
+
 @node GNU Free Documentation License
 @appendix GNU Free Documentation License
 @include fdl.texi
index eeaae16a6bea52adb64cd290b4638d29a85730cf..8d402f14692725ac966e13d05163b109d7d73a00 100644 (file)
@@ -111,7 +111,7 @@ ChangeLog:
     7               *          Position Independence Status: 0 => static, 1 => pic, 2 => PIC, 3 => pie
     8               !+         Short enums
     9..31          <none>      Reserved for future use.
-    32..126         $*         An annotation type not explicitly defined by this specification.
+    32..126         $*!+       An annotation type not explicitly defined by this specification.
     127+           <none>      Reserved for future use.
 
   For * and $ type attributes the value is then appended.
index b0c22f6607f2a45d634237a960c801529b135663..e549a90090b2cab2ea6cbb54b3137ab10a7118cf 100644 (file)
@@ -1,5 +1,5 @@
 /* aarch64.annobin - AArch64 specific parts of the annobin plugin.
-   Copyright (c) 2017 Red Hat.
+   Copyright (c) 2017 - 2018 Red Hat.
    Created by Nick Clifton.
 
   This is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@ annobin_record_global_target_notes (void)
   saved_tls_dialect = aarch64_tls_dialect;
 
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, saved_tls_dialect,
-                              "numeric: ABI: TLS dialect", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                              "numeric: ABI: TLS dialect", NULL, NULL, OPEN);
   annobin_inform (1, "Recording global TLS dialect of %d", saved_tls_dialect);
 }
 
@@ -47,7 +47,7 @@ annobin_target_specific_function_notes (const char * aname, const char * aname_e
 
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, aarch64_tls_dialect,
                               "numeric: ABI: TLS dialect", aname, aname_end,
-                              NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                              FUNC);
 }
 
 typedef struct
index 1c329ee307a67f65943f359e8cb4ac9afe6ad803..e4a3c27ec7318c4cff4dcff6b1a49e37c0003a36 100644 (file)
@@ -1,5 +1,5 @@
 /* annobin - a gcc plugin for annotating binary files.
-   Copyright (c) 2017 Red Hat.
+   Copyright (c) 2017 - 2018 Red Hat.
    Created by Nick Clifton.
 
   This is free software; you can redistribute it and/or modify it
@@ -59,20 +59,23 @@ static bool           annobin_enable_dynamic_notes = true;
 /* True if notes in the .gnu.build.attributes section should be produced.  */
 static bool           annobin_enable_static_notes = true;
 
-static unsigned int   annobin_note_count = 0;
-static unsigned int   global_GOWall_options = 0;
-static int            global_stack_prot_option = -1;
 #ifdef flag_stack_clash_protection
 static int            global_stack_clash_option = -1;
 #endif
+#ifdef flag_cf_protection
+static int            global_cf_option = -1;
+#endif
+static unsigned int   annobin_note_count = 0;
+static unsigned int   global_GOWall_options = 0;
+static int            global_stack_prot_option = -1;
 static int            global_pic_option = -1;
 static int            global_short_enums = -1;
 static char *         compiler_version = NULL;
 static unsigned       verbose_level = 0;
 static char *         annobin_current_filename = NULL;
 static char *         annobin_current_endname  = NULL;
-static unsigned char  annobin_version = 3; /* NB. Keep in sync with version_string below.  */
-static const char *   version_string = N_("Version 3");
+static unsigned char  annobin_version = 4; /* NB. Keep in sync with version_string below.  */
+static const char *   version_string = N_("Version 4");
 static const char *   help_string =  N_("Supported options:\n\
    disable                Disable this plugin\n\
    enable                 Enable this plugin\n\
@@ -193,8 +196,8 @@ annobin_output_note (const char * name,
   if (asm_out_file == NULL)
     return;
 
-  if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC
-      || type == NT_GNU_BUILD_ATTRIBUTE_OPEN)
+  if (type == FUNC
+      || type == OPEN)
     {
       fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME);    
     }
@@ -269,8 +272,8 @@ annobin_output_note (const char * name,
     }
 
   fprintf (asm_out_file, "\t.dc.l %#x\t%s type = %s\n", type, ASM_COMMENT_START,
-          type == NT_GNU_BUILD_ATTRIBUTE_OPEN ? "OPEN" :
-          type == NT_GNU_BUILD_ATTRIBUTE_FUNC ? "FUNC" :
+          type == OPEN ? "OPEN" :
+          type == FUNC ? "FUNC" :
           type == NT_GNU_PROPERTY_TYPE_0      ? "PROPERTY_TYPE_0" : "*UNKNOWN*");
 
   if (name)
@@ -354,8 +357,8 @@ annobin_output_note (const char * name,
        }
     }
 
-  if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC
-      || type == NT_GNU_BUILD_ATTRIBUTE_OPEN)
+  if (type == FUNC
+      || type == OPEN)
     {
       fprintf (asm_out_file, "\t.popsection\n");
       fflush (asm_out_file);
@@ -366,6 +369,21 @@ annobin_output_note (const char * name,
   ++ annobin_note_count;
 }
 
+void
+annobin_output_static_note (const char * buffer,
+                           unsigned     buffer_len,
+                           bool         name_is_string,
+                           const char * name_description,
+                           const char * start,
+                           const char * end,
+                           unsigned     note_type)
+{
+  annobin_output_note (buffer, buffer_len, name_is_string, name_description,
+                      start, end,
+                      start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4: 8)),
+                      true, note_type);
+}
+
 void
 annobin_output_bool_note (const char    bool_type,
                          const bool    bool_value,
@@ -376,16 +394,12 @@ annobin_output_bool_note (const char    bool_type,
 {
   char buffer [6];
 
-  sprintf (buffer, "GA%c%c",
-          bool_value ? GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE : GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE,
-          bool_type);
+  sprintf (buffer, "GA%c%c", bool_value ? BOOL_T : BOOL_F, bool_type);
 
   /* Include the NUL byte at the end of the name "string".
      This is required by the ELF spec.  */
-  annobin_output_note (buffer, strlen (buffer) + 1, false, name_description,
-                      start, end,
-                      start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4: 8)),
-                      true, note_type);
+  annobin_output_static_note (buffer, strlen (buffer) + 1, false, name_description,
+                             start, end, note_type);
 }
 
 void
@@ -403,10 +417,8 @@ annobin_output_string_note (const char    string_type,
 
   sprintf (buffer, "GA%c%c%s", GNU_BUILD_ATTRIBUTE_TYPE_STRING, string_type, string);
 
-  annobin_output_note (buffer, len + 5, true, name_description,
-                      start, end,
-                      start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4 : 8)),
-                      true, note_type);
+  annobin_output_static_note (buffer, len + 5, true, name_description,
+                             start, end, note_type);
 }
 
 void
@@ -420,7 +432,7 @@ annobin_output_numeric_note (const char     numeric_type,
   unsigned i;
   char buffer [32];
   
-  sprintf (buffer, "GA%c%c", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC, numeric_type);
+  sprintf (buffer, "GA%c%c", NUMERIC, numeric_type);
 
   if (value == 0)
     {
@@ -451,10 +463,8 @@ annobin_output_numeric_note (const char     numeric_type,
   if (value)
     annobin_inform (0, "ICE: Unable to record numeric value in note %s\n", name_description);
 
-  annobin_output_note (buffer, i + 1, false, name_description,
-                      start, end,
-                      start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4 : 8)),
-                      true, note_type);
+  annobin_output_static_note (buffer, i + 1, false, name_description,
+                             start, end, note_type);
 }
 
 static int
@@ -547,7 +557,7 @@ record_GOW_settings (unsigned int gow, bool local, const char * cname, const cha
   char buffer [128];
   unsigned i;
 
-  (void) sprintf (buffer, "GA%cGOW", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC);
+  (void) sprintf (buffer, "GA%cGOW", NUMERIC);
 
   for (i = 7; i < sizeof buffer; i++)
     {
@@ -565,13 +575,13 @@ record_GOW_settings (unsigned int gow, bool local, const char * cname, const cha
       annobin_inform (1, "Record a change in -g/-O/-Wall status for %s", cname);
       annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall",
                           aname, aname_end, annobin_is_64bit ? 16 : 8, true,
-                          NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                          FUNC);
     }
   else
     {
       annobin_inform (1, "Record status of -g/-O/-Wall");
       annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall",
-                          NULL, NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                          NULL, NULL, 0, false, OPEN);
     }
 }
 
@@ -581,17 +591,31 @@ record_stack_clash_note (const char * start, const char * end, int type)
 {
   char buffer [128];
   unsigned len = sprintf (buffer, "GA%cstack_clash",
-                         flag_stack_clash_protection
-                         ? GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE
-                         : GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE);
+                         flag_stack_clash_protection ? BOOL_T : BOOL_F);
 
-  annobin_output_note (buffer, len + 1, true, "bool: -fstack-clash-protection status",
-                      start, end,
-                      start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4: 8)),
-                      true, type);
+  annobin_output_static_note (buffer, len + 1, true, "bool: -fstack-clash-protection status",
+                             start, end, type);
 }
 #endif
 
+#ifdef flag_cf_protection
+static void
+record_cf_protection_note (const char * start, const char * end, int type)
+{
+  char buffer [128];
+  unsigned len = sprintf (buffer, "GA%ccf_protection", NUMERIC);
+
+  /* We bias the flag_cf_protection enum value by 1 so that we do not get confused by a zero value.  */
+  buffer[++len] = flag_cf_protection + 1;
+  buffer[++len] = 0;
+
+  annobin_inform (1, "Record cf-protection status of %d", flag_cf_protection);
+  annobin_output_static_note (buffer, len + 1, false, "numeric: -fcf-protection status",
+                             start, end, type);
+}
+#endif
+
+
 static void
 annobin_create_function_notes (void * gcc_data, void * user_data)
 {
@@ -638,7 +662,7 @@ annobin_create_function_notes (void * gcc_data, void * user_data)
 
       annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, flag_stack_protect,
                                   "numeric: -fstack-protector status",
-                                  aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                                  aname, aname_end, FUNC);
 
       if (aname != NULL)
        aname = aname_end = NULL;
@@ -650,7 +674,20 @@ annobin_create_function_notes (void * gcc_data, void * user_data)
       annobin_inform (1, "Recording change in stack clash protection status for %s (from %d to %d)",
                      cname, global_stack_clash_option, flag_stack_clash_protection);
 
-      record_stack_clash_note (aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC);
+      record_stack_clash_note (aname, aname_end, FUNC);
+
+      if (aname != NULL)
+       aname = aname_end = NULL;
+    }
+#endif
+  
+#ifdef flag_cf_protection
+  if (global_cf_option != flag_cf_protection)
+    {
+      annobin_inform (1, "Recording change in control flow protection status for %s (from %d to %d)",
+                     cname, global_cf_option, flag_cf_protection);
+
+      record_cf_protection_note (aname, aname_end, FUNC);
 
       if (aname != NULL)
        aname = aname_end = NULL;
@@ -662,7 +699,7 @@ annobin_create_function_notes (void * gcc_data, void * user_data)
       annobin_inform (1, "Recording change in PIC status for %s", cname);
       annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, compute_pic_option (),
                                   "numeric: pic type", aname, aname_end,
-                                  NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                                  FUNC);
       if (aname != NULL)
        aname = aname_end = NULL;
     }
@@ -680,7 +717,7 @@ annobin_create_function_notes (void * gcc_data, void * user_data)
       annobin_inform (1, "Recording change in enum size for %s", cname);
       annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, flag_short_enums,
                                flag_short_enums ? "bool: short-enums: on" : "bool: short-enums: off",
-                               aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                               aname, aname_end, FUNC);
       if (aname != NULL)
        aname = aname_end = NULL;
     }
@@ -696,7 +733,7 @@ annobin_create_function_notes (void * gcc_data, void * user_data)
                                       current_function_static_stack_size,
                                       "numeric: stack-size",
                                       aname, aname_end,
-                                      NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                                      FUNC);
          if (aname != NULL)
            aname = aname_end = NULL;
        }
@@ -722,12 +759,12 @@ static void
 record_fortify_level (int level)
 {
   char buffer [128];
-  unsigned len = sprintf (buffer, "GA%cFORTIFY", GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC);
+  unsigned len = sprintf (buffer, "GA%cFORTIFY", NUMERIC);
 
   buffer[++len] = level;
   buffer[++len] = 0;
   annobin_output_note (buffer, len + 1, false, "FORTIFY SOURCE level",
-                      NULL, NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                      NULL, NULL, 0, false, OPEN);
   annobin_inform (1, "Record a FORTIFY SOURCE level of %d", level);
 }
 
@@ -735,11 +772,10 @@ static void
 record_glibcxx_assertions (bool on)
 {
   char buffer [128];
-  unsigned len = sprintf (buffer, "GA%cGLIBCXX_ASSERTIONS",
-                         on ? GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE : GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE);
+  unsigned len = sprintf (buffer, "GA%cGLIBCXX_ASSERTIONS", on ? BOOL_T : BOOL_F);
 
   annobin_output_note (buffer, len + 1, false, "_GLIBCXX_ASSERTIONS defined",
-                      NULL, NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                      NULL, NULL, 0, false, OPEN);
   annobin_inform (1, "Record a _GLIBCXX_ASSERTIONS as %s", on ? "defined" : "not defined");
 }
 
@@ -785,10 +821,13 @@ annobin_create_global_notes (void * gcc_data, void * user_data)
     /* We must set this flag in order to obtain per-function stack usage info.  */
     flag_stack_usage_info = 1;
 
-  global_stack_prot_option = flag_stack_protect;
 #ifdef flag_stack_clash_protection
   global_stack_clash_option = flag_stack_clash_protection;
 #endif
+#ifdef flag_cf_protection
+  global_cf_option = flag_cf_protection;
+#endif
+  global_stack_prot_option = flag_stack_protect;
   global_pic_option = compute_pic_option ();
   global_short_enums = flag_short_enums;
   global_GOWall_options = compute_GOWall_options ();
@@ -827,11 +866,11 @@ annobin_create_global_notes (void * gcc_data, void * user_data)
                              "string: version",
                              annobin_current_filename,
                              annobin_current_endname,
-                             NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                             OPEN);
 
   /* Record the version of the compiler.  */
   annobin_output_string_note (GNU_BUILD_ATTRIBUTE_TOOL, compiler_version,
-                             "string: build-tool", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                             "string: build-tool", NULL, NULL, OPEN);
 
   /* Record optimization level, -W setting and -g setting  */
   record_GOW_settings (global_GOWall_options, false, NULL, NULL, NULL);
@@ -839,11 +878,15 @@ annobin_create_global_notes (void * gcc_data, void * user_data)
   /* Record -fstack-protector option.  */
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, global_stack_prot_option,
                               "numeric: -fstack-protector status",
-                              NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                              NULL, NULL, OPEN);
 
 #ifdef flag_stack_clash_protection
   /* Record -fstack-clash-protection option.  */
-  record_stack_clash_note (NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+  record_stack_clash_note (NULL, NULL, OPEN);
+#endif
+#ifdef flag_cf_protection
+  /* Record -fcf-protection option.  */
+  record_cf_protection_note (NULL, NULL, OPEN);
 #endif
 
   /* Look for -D _FORTIFY_SOURCE=<n> on the original gcc command line.
@@ -913,12 +956,12 @@ annobin_create_global_notes (void * gcc_data, void * user_data)
   
   /* Record the PIC status.  */
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, global_pic_option,
-                              "numeric: PIC", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                              "numeric: PIC", NULL, NULL, OPEN);
 
   /* Record enum size.  */
   annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, global_short_enums,
                            global_short_enums ? "bool: short-enums: on" : "bool: short-enums: off",
-                           NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                           NULL, NULL, OPEN);
 
   /* Record target specific notes.  */
   annobin_record_global_target_notes ();
@@ -947,7 +990,7 @@ annobin_create_loader_notes (void * gcc_data, void * user_data)
 
       fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME);    
       annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, annobin_total_static_stack_usage,
-                                  "numeric: stack-size", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                                  "numeric: stack-size", NULL, NULL, OPEN);
       fprintf (asm_out_file, "\t.popsection\n");
     }
 
index e1b9e14e93b38f52829fa949dccadaf8d423697b..eaf315b2aca6e514c74260229d9bbbfe4684f583 100644 (file)
@@ -1,5 +1,5 @@
 /* annobin - Header file for the gcc plugin for annotating binary files.
-   Copyright (c) 2017 Red Hat.
+   Copyright (c) 2017 - 2018 Red Hat.
    Created by Nick Clifton.
 
   This is free software; you can redistribute it and/or modify it
@@ -53,6 +53,15 @@ extern struct plugin_gcc_version gcc_version ATTRIBUTE_UNUSED;
 #define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE     '+'
 #define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE    '!'
 
+/* Short-hand versions of the above defines.  */
+#define OPEN NT_GNU_BUILD_ATTRIBUTE_OPEN
+#define FUNC NT_GNU_BUILD_ATTRIBUTE_FUNC
+
+#define NUMERIC GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC
+#define STRING  GNU_BUILD_ATTRIBUTE_TYPE_STRING
+#define BOOL_T  GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE
+#define BOOL_F  GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE
+
 #define GNU_BUILD_ATTRIBUTE_VERSION    1
 #define GNU_BUILD_ATTRIBUTE_STACK_PROT 2
 #define GNU_BUILD_ATTRIBUTE_RELRO      3
@@ -92,6 +101,7 @@ extern void annobin_target_specific_loader_notes (void);
 
 extern void annobin_inform (unsigned, const char *, ...);
 extern void annobin_output_note (const char *, unsigned, bool, const char *, const char *, const char *, unsigned, bool, unsigned);
+extern void annobin_output_static_note (const char *, unsigned, bool, const char *, const char *, const char *, unsigned);
 extern void annobin_output_bool_note (const char, const bool, const char *, const char *, const char *, unsigned);
 extern void annobin_output_string_note (const char, const char *, const char *, const char *, const char *, unsigned);
 extern void annobin_output_numeric_note (const char, unsigned long, const char *, const char *, const char *, unsigned);
index ff9017e5e82d08a4a597b4cba758b06cafc8d7c1..669fa7df5173947d1dd8965de41b5ec67cfcd3d8 100644 (file)
@@ -1,5 +1,5 @@
 /* powerpc64le.annobin - PowerPC64 specific parts of the annobin plugin.
-   Copyright (c) 2017 Red Hat.
+   Copyright (c) 2017 - 2018 Red Hat.
    Created by Nick Clifton.
 
   This is free software; you can redistribute it and/or modify it
@@ -31,8 +31,7 @@ annobin_record_global_target_notes (void)
   saved_tls_size = rs6000_tls_size;
   
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, saved_tls_size,
-                              "numeric: ABI: TLS size", NULL, NULL,
-                              NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                              "numeric: ABI: TLS size", NULL, NULL, OPEN);
   annobin_inform (1, "Recording global TLS size of %d", saved_tls_size);
 }
 
@@ -46,8 +45,7 @@ annobin_target_specific_function_notes (const char * aname, const char * aname_e
                  saved_tls_size, rs6000_tls_size, aname);
 
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, rs6000_tls_size,
-                              "numeric: ABI: TLS size", aname, aname_end,
-                              NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                              "numeric: ABI: TLS size", aname, aname_end, FUNC);
 }
 
 typedef struct
index 3fc5b9c8d64c8555008c421ab0523e5862e90357..b3207fd3a44a6afa198b95a78d26230dc4083930 100644 (file)
@@ -1,5 +1,5 @@
 /* x86_64.annobin - x86_64 specific parts of the annobin plugin.
-   Copyright (c) 2017 Red Hat.
+   Copyright (c) 2017 - 2018 Red Hat.
    Created by Nick Clifton.
 
   This is free software; you can redistribute it and/or modify it
 #define GNU_PROPERTY_X86_ISA_1_AVX512DQ      (1U << 16)
 #define GNU_PROPERTY_X86_ISA_1_AVX512BW      (1U << 17)
 
-
 static unsigned long global_x86_isa = 0;
 static unsigned long min_x86_isa = 0;
 static unsigned long max_x86_isa = 0;
 
+#ifdef flag_cet
+static int                     global_cet = -1;
+static int                     global_set_switch = -1;
+static unsigned HOST_WIDE_INT  global_ibt = 0;
+static unsigned HOST_WIDE_INT  global_shstk = 0;
+#endif
+
 void
 annobin_save_target_specific_information (void)
 {
 }
 
+#ifdef flag_cet
+static void
+record_cet_note (const char * start, const char * end, int type)
+{
+  char buffer [128];
+  unsigned len = sprintf (buffer, "GA%ccet status", NUMERIC);
+
+  /* We bias the values by 1 so that we do not get confused by a zero value.  */
+  buffer[++len] = flag_cet + 1;
+  buffer[++len] = flag_cet_switch + 1;
+  buffer[++len] = (ix86_isa_flags2 & OPTION_MASK_ISA_IBT) ? 2 : 1;
+  buffer[++len] = (ix86_isa_flags & OPTION_MASK_ISA_SHSTK) ? 2 : 1;
+  buffer[++len] = 0;
+
+  annobin_inform (1, "Record CET values of %d:%d:%lx:%lx",
+                 flag_cet, flag_cet_switch,
+                 ix86_isa_flags2 & OPTION_MASK_ISA_IBT,
+                 ix86_isa_flags & OPTION_MASK_ISA_SHSTK);
+
+  annobin_output_static_note (buffer, len + 1, false, "numeric: -mcet status",
+                             start, end, type);
+}
+#endif
+
 void
 annobin_record_global_target_notes (void)
 {
@@ -56,9 +86,17 @@ annobin_record_global_target_notes (void)
   min_x86_isa = max_x86_isa = global_x86_isa = ix86_isa_flags;
 
   annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, global_x86_isa,
-                              "numeric: ABI", NULL, NULL,
-                              NT_GNU_BUILD_ATTRIBUTE_OPEN);
+                              "numeric: ABI", NULL, NULL, OPEN);
   annobin_inform (1, "Record global isa of %lx", global_x86_isa);
+
+#ifdef flag_cet
+  global_cet = flag_cet;
+  global_set_switch = flag_cet_switch;
+  global_ibt = ix86_isa_flags2 & OPTION_MASK_ISA_IBT;
+  global_shstk = ix86_isa_flags & OPTION_MASK_ISA_SHSTK;
+
+  record_cet_note (NULL, NULL, OPEN);
+#endif
 }
 
 void
@@ -70,14 +108,38 @@ annobin_target_specific_function_notes (const char * aname, const char * aname_e
                   global_x86_isa, ix86_isa_flags, aname);
 
       annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, ix86_isa_flags,
-                                  "numeric: ABI", aname, aname_end,
-                                  NT_GNU_BUILD_ATTRIBUTE_FUNC);
+                                  "numeric: ABI", aname, aname_end, FUNC);
 
       if ((unsigned long) ix86_isa_flags < min_x86_isa)
        min_x86_isa = ix86_isa_flags;
       if ((unsigned long) ix86_isa_flags > max_x86_isa)
        max_x86_isa = ix86_isa_flags;
     }
+  
+#ifdef flag_cet
+  if (global_cet != flag_cet)
+    fprintf (stderr, "1\n");
+  if (global_set_switch != flag_cet_switch)
+    fprintf (stderr, "2\n");
+  if (global_ibt != (ix86_isa_flags2 & OPTION_MASK_ISA_IBT))
+    fprintf (stderr, "3\n");
+  if (global_shstk != (ix86_isa_flags & OPTION_MASK_ISA_SHSTK))
+    fprintf (stderr, "4\n");
+      
+  if ((global_cet != flag_cet)
+      || (global_set_switch != flag_cet_switch)
+      || (global_ibt != (ix86_isa_flags2 & OPTION_MASK_ISA_IBT))
+      || (global_shstk != (ix86_isa_flags & OPTION_MASK_ISA_SHSTK)))
+    {
+      annobin_inform (0, "CET values have changed from %d:%d:%lx:%lx to %d:%d:%lx:%lx",
+                     global_cet, global_set_switch, global_ibt, global_shstk,
+                     flag_cet, flag_cet_switch,
+                     (ix86_isa_flags2 & OPTION_MASK_ISA_IBT),
+                     (ix86_isa_flags & OPTION_MASK_ISA_SHSTK));
+       
+      record_cet_note (aname, aname_end, FUNC);
+    }
+#endif
 }
 
 static unsigned int
index 15ea3ce9e0d4f2e7d45ddf3ec898b2f3d353cb31..c052fa33f8d225ec3feb3c4cde0ec414c2d3f3f9 100755 (executable)
@@ -57,6 +57,13 @@ Plus for executables (although on RHEL6 these should be omitted due to a kernel
    -fPIE
    -Wl,-pie
 
+Plus for RHEL-8:
+
+   -D_GLIBCXX_ASSERTIONS
+   -fstack-clash-protection
+   -fcf-protection=full
+   -mcet
+
 Usage: $prog {files|options}
 
  {options} are:
@@ -84,6 +91,8 @@ Usage: $prog {files|options}
   -k=pic      --skip=pic       Skip check for PIC/PIE compilation.  (Good for RHEL-6 binaries)
   -k=operator --skip=operator  Skip check for operator[] range testing.
   -k=clash    --skip=clash     Skip check for stack clash protection.
+  -k=cf       --skip=cf        Skip check for control flow protection.
+  -k=cet      --skip-cet       Skip check for control flow enforcement technology.
  [These options stack]
   
   -i        --ignore-unknown   Silently skip any file that is not an ELF binary.
@@ -176,6 +185,7 @@ init ()
     report=1 # Quad-state, 0=> report nothing, 1=> report known vulnerable, 2=> report not proven hardened, 3=> report all
     verb=0
     filetype=auto
+
     skip_opt=0
     skip_stack=0
     skip_fortify=0
@@ -184,6 +194,9 @@ init ()
     skip_pic=0
     skip_operator=0
     skip_clash=0
+    skip_cf=0
+    skip_cet=0
+    
     ignore_unknown=0
     scanner=readelf
     tmpfile=/dev/shm/hardened.delme
@@ -272,6 +285,12 @@ parse_args ()
                    clash)
                        skip_clash=1;
                        ;;
+                   cf)
+                       skip_cf=1;
+                       ;;
+                   cet)
+                       skip_cet=1;
+                       ;;
                    *)
                        report "unknown option skip: $optarg"
                        ;;
@@ -416,10 +435,7 @@ scan_file ()
        # The other checks can use other sources of information.
        if [ $skip_fortify -eq 0 ];
        then
-           report "scanner '$scanner' did not recognise the build attribute notes - see $tmpfile"
-           failed=1
-           # Leave the tmpfile intact so that it can be examined by the user.
-           return
+           maybe "scanner '$scanner' did not recognise the build attribute notes "
        fi
     fi       
 
@@ -476,6 +492,17 @@ scan_file ()
        check_stack_clash
     fi
 
+    if [ $skip_cf -eq 0 ];
+    then
+       check_control_flow_protection
+    fi
+
+    # FIXME: This check should only be applied to x86_64 binaries...
+    if [ $skip_cet -eq 0 ];
+    then
+       check_control_flow_enforcement_technology
+    fi
+
     # If we found a vulnerable file then consider the check to have failed.
     if [ $vulnerable -gt 0 ];
     then
@@ -775,8 +802,6 @@ check_operator_range ()
            fi
        fi
     fi
-
-    # FIXME: Do we need to check for individual functions compiled without range checking ?
 }
 
 check_stack_clash ()
@@ -805,8 +830,78 @@ check_stack_clash ()
            fi
        fi
     fi
+}
 
-    # FIXME: Do we need to check for individual functions compiled without protection ?
+check_control_flow_protection ()
+{
+    # Turn:
+    #   GA*cf_protection:0x8          0x00000000       OPEN        Applies to region from 0 to 0x3a
+    # into:
+    #   0x8
+    eval 'hard=($(grep -e "cf_protection" $tmpfile | cut -f 2 -d ":" | cut -f 1 -d " " | sort -u))'
+
+    verbose "Control Flow Info: ${hard[*]}"
+
+    if [ ${#hard[*]} -lt 1 ];
+    then
+       maybe "does not record control flow protection setting"
+    else
+       if [ ${#hard[*]} -gt 1 ];
+       then
+           fail "some parts built with different settings for -fcf-protection"
+       else
+           if [ "x${hard[0]}" == "x0x8" ];
+           then
+               pass "compiled with -fcf-protection=full"
+           else
+               if [ "x${hard[0]}" == "x0x7" ];
+               then
+                   fail "compiled with -fcf-protection=return"
+               else
+                   if [ "x${hard[0]}" == "x0x5" ];
+                   then
+                       fail "compiled with -fcf-protection=branch"
+                   else
+                       fail "compiled with unknown setting for -fcf-protection"
+                   fi
+               fi
+           fi
+       fi
+    fi
+}
+
+check_control_flow_enforcement_technology ()
+{
+    # Turn:
+    #   GA*cet status:0x2020102          0x00000000    OPEN        Applies to region from 0 to 0x3a
+    # into:
+    #   0x2020102
+    eval 'hard=($(grep -e "cet status" $tmpfile | cut -f 2 -d ":" | cut -f 1 -d " " | sort -u))'
+
+    verbose "CET Info: ${hard[*]}"
+
+    if [ ${#hard[*]} -lt 1 ];
+    then
+       maybe "does not record control flow enforcement technology setting"
+    else
+       if [ ${#hard[*]} -gt 1 ];
+       then
+           fail "some parts built different CET settings"
+       else
+           if [ "x${hard[0]}" == "x0x2020102" ];
+           then
+               pass "compiled with CET enabled"
+           else
+               if [ "x${hard[0]}" == "x0x2020202" ];
+               then
+                   pass "compiled with CET enabled (and switch protection)"
+               else
+                   # FIXME: Tell the user exactly which bits were not enabled.
+                   fail "compiled with CET disabled"
+               fi
+           fi
+       fi
+    fi
 }
 
 
index 5885c385f85b7f588b2291aa6c6bc74866633eee..f0430241390a037cae40c0ab0cc47d6658b7cc5e 100644 (file)
@@ -9,3 +9,5 @@
 TESTS=compile-test hardening-test hardening-fail-test abi-test missing-notes-test
 XFAIL_TESTS=hardening-fail-test
 
+# FIXME: Add a test for merging notes...
+
index 212e01dfb95b6f9c0d049c07563c5b2ec54e8e9f..0ef195e268afd8c7c93b882191b6ae6243afcfa4 100755 (executable)
@@ -64,11 +64,5 @@ $GCC -fplugin=$PLUGIN \
 
 # $OBJCOPY --merge-notes hardening-fail-test.exe hardening-fail-test-merged.exe
 
-# The --skip=fort option is here to skip the check of _FORTIFY_SOURCE as this
-# requires a version of readelf that knows how to fully parse the annobin notes
-# and such a version is not in common release (yet).  The other hardening
-# properties can be deduced by the hardened.sh script without needing the notes
-# so that is why the test is allowed to proceed.
-# FIXME: Remove --skip=fort once readelf has been updated.
-$srcdir/../scripts/hardened.sh  --readelf=$READELF --all hardening-fail-test.exe --skip=fort
+$srcdir/../scripts/hardened.sh  --readelf=$READELF --all hardening-fail-test.exe
 
index 7ee494aae48c3832cdf4ba1b219aaf57aaf69074..e9c3357feb3c129d95eb8b4a3cfaff9130ee49f5 100755 (executable)
@@ -37,10 +37,14 @@ $GCC -fplugin=$PLUGIN \
 
 # $OBJCOPY --merge-notes hardening-test.exe hardening-test-merged.exe
 
-# The --skip={fort|clash|operator} options are here to skip the checks that
-# requires a version of readelf that knows how to fully parse v3 annobin notes.
-# Such a version is not in common release (yet).  The other hardening
-# properties can be deduced by the hardened.sh script without needing the notes
-# so that is why the test is allowed to proceed.
-# FIXME: Remove the --skip= options once readelf has been updated.
-$srcdir/../scripts/hardened.sh  --readelf=$READELF --all --skip=fort -k=operator --skip=clash hardening-test.exe
+# The --skip=... options are here to skip the checks that require a version
+# 2.30 (or later) readelf, and which were generated by a plugin attached to
+# a version 8 (or later) gcc.  Since neither of these versions of the tools
+# are in common use (yet) the checks are disabled.
+# The other hardening properties can be deduced by the hardened.sh script
+# without needing the notes produced by annobin, so that is why the test is
+# allowed to proceed.
+# FIXME: Remove the --skip= options once readelf and gcc have been updated.
+$srcdir/../scripts/hardened.sh  --readelf=$READELF \
+  --skip=fort -k=operator --skip=clash --skip=cf -k=cet \
+  hardening-test.exe
This page took 0.061461 seconds and 5 git commands to generate.