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
* 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:
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
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
==============================================
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
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
@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
@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
@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
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
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
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.
/* 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
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);
}
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
/* 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
/* 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\
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);
}
}
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)
}
}
- 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);
++ 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,
{
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
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
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)
{
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
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++)
{
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);
}
}
{
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)
{
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;
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;
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;
}
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;
}
current_function_static_stack_size,
"numeric: stack-size",
aname, aname_end,
- NT_GNU_BUILD_ATTRIBUTE_FUNC);
+ FUNC);
if (aname != NULL)
aname = aname_end = NULL;
}
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);
}
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");
}
/* 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 ();
"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);
/* 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.
/* 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 ();
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");
}
/* 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
#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
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);
/* 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
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);
}
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
/* 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)
{
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
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
-fPIE
-Wl,-pie
+Plus for RHEL-8:
+
+ -D_GLIBCXX_ASSERTIONS
+ -fstack-clash-protection
+ -fcf-protection=full
+ -mcet
+
Usage: $prog {files|options}
{options} are:
-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.
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
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
clash)
skip_clash=1;
;;
+ cf)
+ skip_cf=1;
+ ;;
+ cet)
+ skip_cet=1;
+ ;;
*)
report "unknown option skip: $optarg"
;;
# 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
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
fi
fi
fi
-
- # FIXME: Do we need to check for individual functions compiled without range checking ?
}
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
}
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...
+
# $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
# $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