From 8148a1e572d9f6922092d547f1bbb6223a779285 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 5 Jul 2018 10:40:11 +0100 Subject: [PATCH] Do not skip empty range notes in object files. Refact function note generation to allow for function sections. --- annocheck/annocheck.c | 85 +++++++---- annocheck/annocheck.h | 54 +++---- annocheck/built-by.c | 24 +-- annocheck/hardened.c | 149 ++++++++++--------- plugin/aarch64.annobin.cc | 8 +- plugin/annobin.cc | 305 +++++++++++++++++++++++++++----------- plugin/annobin.h | 8 +- plugin/dummy.annobin.cc | 4 +- plugin/powerpc.annobin.cc | 8 +- plugin/x86_64.annobin.cc | 41 ++--- tests/hardening-fail-test | 42 +----- tests/unused_code.c | 42 ++++++ 12 files changed, 481 insertions(+), 289 deletions(-) diff --git a/annocheck/annocheck.c b/annocheck/annocheck.c index 6f86fd8..1ad7a1b 100644 --- a/annocheck/annocheck.c +++ b/annocheck/annocheck.c @@ -239,7 +239,6 @@ process_command_line (uint argc, const char * argv[]) const char * arg = argv[a]; bool used = false; checker * tool; - const char * parameter; ++ a; @@ -260,6 +259,7 @@ process_command_line (uint argc, const char * argv[]) if (arg[0] == '-') { + const char * parameter; const char * orig_arg = arg; arg += (arg[1] == '-' ? 2 : 1); @@ -279,19 +279,45 @@ process_command_line (uint argc, const char * argv[]) break; case 'd': - save_arg (orig_arg); - bool is_path = arg[1] == 'w'; parameter = strchr (arg, '='); if (parameter == NULL) parameter = argv[a++]; else parameter ++; - if (is_path) + + if (strncmp (arg, "dwarf-dir", 9) == 0) dwarf_path = parameter; - else + else if (strncmp (arg, "debug-rpm", 9) == 0) debug_rpm = parameter; + else + goto unknown_arg; + + if (parameter[0] != '/') + { + const char * tmp; + /* Convert a relative path to an absolute one so that if/when + we recurse into a directory, the path will remain valid. */ + if (parameter == argv[a-1]) + tmp = concat (orig_arg, " ", getcwd (NULL, 0), "/", parameter, NULL); + else + tmp = concat (orig_arg, getcwd (NULL, 0), "/", parameter, NULL); + save_arg (tmp); + free ((void *) tmp); + } + else + { + save_arg (orig_arg); + if (parameter == argv[a-1]) + save_arg (parameter); + } + if (dwarf_path != NULL && debug_rpm != NULL) - einfo (WARN, "Behaviour is udnefined with both --debug-rpm and --dwarf-dir"); + { + static bool warned = false; + if (! warned) + einfo (WARN, "Behaviour is udnefined when both --debug-rpm and --dwarf-dir are specified"); + warned = true; + } break; case 'p': @@ -351,7 +377,7 @@ process_command_line (uint argc, const char * argv[]) Returns FALSE if the walk could not be executed. */ bool -eu_checksec_walk_notes (eu_checksec_data * data, eu_checksec_section * sec, note_walker func, void * ptr) +annocheck_walk_notes (annocheck_data * data, annocheck_section * sec, note_walker func, void * ptr) { assert (data != NULL && sec != NULL && func != NULL); @@ -376,7 +402,7 @@ eu_checksec_walk_notes (eu_checksec_data * data, eu_checksec_section * sec, note /* Read in the section header for SECTION. */ static void -read_section_header (eu_checksec_data * data, Elf_Scn * section, Elf64_Shdr * s64hdr) +read_section_header (annocheck_data * data, Elf_Scn * section, Elf64_Shdr * s64hdr) { if (data->is_32bit) { @@ -402,7 +428,7 @@ read_section_header (eu_checksec_data * data, Elf_Scn * section, Elf64_Shdr * s6 static bool run_checkers (const char * filename, int fd, Elf * elf) { - eu_checksec_data data; + annocheck_data data; memset (& data, 0, sizeof data); data.full_filename = filename; @@ -435,7 +461,7 @@ run_checkers (const char * filename, int fd, Elf * elf) while ((scn = elf_nextscn (elf, scn)) != NULL) { - eu_checksec_section sec; + annocheck_section sec; memset (& sec, 0, sizeof sec); @@ -493,7 +519,7 @@ run_checkers (const char * filename, int fd, Elf * elf) for (cnt = 0; cnt < phnum; ++cnt) { GElf_Phdr mem; - eu_checksec_segment seg; + annocheck_segment seg; memset (& seg, 0, sizeof seg); @@ -563,11 +589,21 @@ extract_rpm_file (const char * filename) char * command; char * cwd = getcwd (NULL, 0); + /* If filename is a relative path, convert it to an absolute one + so that it can be found once we change into the temporary directory. */ if (filename[0] != '/') fname = concat (cwd, "/", filename, NULL); else + /* This is just so that we can safely call free(fname) at the end. */ fname = concat (filename, NULL); + if (access (fname, F_OK) == -1) + { + einfo (SYS_ERROR, "Error reading rpm file file %s", fname); + free (fname); + return NULL; + } + command = concat (/* Change into the temporary directory. */ "cd ", dirname, /* Convert the rpm to cpio format. */ @@ -604,7 +640,7 @@ extract_rpm_file (const char * filename) while (0) static Dwarf * -follow_debuglink (eu_checksec_data * data, Dwarf * dwarf) +follow_debuglink (annocheck_data * data, Dwarf * dwarf) { char * canon_dir = NULL; char * debugfile = NULL; @@ -628,7 +664,7 @@ follow_debuglink (eu_checksec_data * data, Dwarf * dwarf) where NNNN+NN is the build-id value as a hexadecimal string. */ - const char * path; + const char * path = NULL; const char * leadin = "/usr/lib/debug/.build-id/"; unsigned char * d = (unsigned char *) build_id_ptr; char build_id_dir[3]; @@ -643,7 +679,8 @@ follow_debuglink (eu_checksec_data * data, Dwarf * dwarf) path = extract_rpm_file (debug_rpm); else if (dwarf_path) path = dwarf_path; - else + + if (path == NULL) path = ""; debugfile = n = xmalloc (strlen (leadin) @@ -810,7 +847,7 @@ follow_debuglink (eu_checksec_data * data, Dwarf * dwarf) /* -------------------------------------------------------------------- */ static bool -scan_dwarf (eu_checksec_data * data, Dwarf * dwarf, dwarf_walker func, void * ptr) +scan_dwarf (annocheck_data * data, Dwarf * dwarf, dwarf_walker func, void * ptr) { Dwarf_Off cuoffset; Dwarf_Off ncuoffset = 0; @@ -840,7 +877,7 @@ scan_dwarf (eu_checksec_data * data, Dwarf * dwarf, dwarf_walker func, void * pt Returns FALSE if the walk could not be executed. */ bool -eu_checksec_walk_dwarf (eu_checksec_data * data, dwarf_walker func, void * ptr) +annocheck_walk_dwarf (annocheck_data * data, dwarf_walker func, void * ptr) { Dwarf * dwarf; @@ -889,9 +926,9 @@ find_symbol_in (Elf * elf, Elf_Scn * sym_sec, ulong addr, Elf64_Shdr * sym_hdr, bool use_saved = false; GElf_Sym saved_sym; GElf_Sym sym; - int symndx = 1; + unsigned int symndx; - while (gelf_getsym (sym_data, symndx, & sym) != NULL) + for (symndx = 1; gelf_getsym (sym_data, symndx, & sym) != NULL; symndx++) { if (sym.st_value >= addr && sym.st_value <= addr + 2) { @@ -912,8 +949,6 @@ find_symbol_in (Elf * elf, Elf_Scn * sym_sec, ulong addr, Elf64_Shdr * sym_hdr, use_sym = true; break; } - - symndx++; } if (use_sym) @@ -934,7 +969,7 @@ typedef struct walker_info } walker_info; static bool -find_symbol_addr_using_dwarf (eu_checksec_data * data, Dwarf * dwarf, Dwarf_Die * die, void * ptr) +find_symbol_addr_using_dwarf (annocheck_data * data, Dwarf * dwarf, Dwarf_Die * die, void * ptr) { assert (data != NULL && die != NULL && ptr != NULL); @@ -1001,8 +1036,8 @@ find_symbol_addr_using_dwarf (eu_checksec_data * data, Dwarf * dwarf, Dwarf_Die Returns NULL if no symbol could be found. */ const char * -eu_checksec_find_symbol_for_address_range (eu_checksec_data * data, - eu_checksec_section * sec, +annocheck_find_symbol_for_address_range (annocheck_data * data, + annocheck_section * sec, ulong start, ulong end, bool prefer_func) @@ -1060,7 +1095,7 @@ eu_checksec_find_symbol_for_address_range (eu_checksec_data * data, walker.end = end; walker.name = & name; walker.prefer_func = prefer_func; - eu_checksec_walk_dwarf (data, find_symbol_addr_using_dwarf, & walker); + annocheck_walk_dwarf (data, find_symbol_addr_using_dwarf, & walker); return previous_result = name; } @@ -1330,7 +1365,7 @@ main (int argc, const char ** argv) /* -------------------------------------------------------------------- */ bool -eu_checksec_add_checker (struct checker * new_checker, uint major) +annocheck_add_checker (struct checker * new_checker, uint major) { if (major < major_version) return false; diff --git a/annocheck/annocheck.h b/annocheck/annocheck.h index 8076f85..7feead0 100644 --- a/annocheck/annocheck.h +++ b/annocheck/annocheck.h @@ -11,8 +11,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ -#ifndef __EU_CHECKSEC_H__ -#define __EU_CHECKSEC_H__ +#ifndef __ANNOCHECK_H__ +#define __ANNOCHECK_H__ #define _GNU_SOURCE #include @@ -65,7 +65,7 @@ typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; -typedef struct eu_checksec_data +typedef struct annocheck_data { const char * filename; const char * full_filename; @@ -75,22 +75,22 @@ typedef struct eu_checksec_data Elf_Data * syms; Dwarf * dwarf; bool dwarf_searched; -} eu_checksec_data; +} annocheck_data; -typedef struct eu_checksec_section +typedef struct annocheck_section { const char * secname; Elf_Scn * scn; Elf64_Shdr shdr; Elf_Data * data; -} eu_checksec_section; +} annocheck_section; -typedef struct eu_checksec_segment +typedef struct annocheck_segment { GElf_Phdr * phdr; uint number; Elf_Data * data; -} eu_checksec_segment; +} annocheck_segment; typedef struct checker { @@ -99,42 +99,42 @@ typedef struct checker /* Called before starting the check of a file. Can be NULL. The section_headers and segment_headers fields will not have been initialised. */ - void (* start) (eu_checksec_data * DATA); + void (* start) (annocheck_data * DATA); /* Called to see if the checker is interested in the particular section. Can be NULL. If NULL, all sections are ignored. If FALSE is returned the section is not processed any further. Note - called even if there are segments in the file. Note - SECTION->data may not be initialised at this point. */ - bool (* interesting_sec) (eu_checksec_data * DATA, - eu_checksec_section * SECTION); + bool (* interesting_sec) (annocheck_data * DATA, + annocheck_section * SECTION); /* Called to check a section. If interesting_sec is not NULL, then this field cannot be NULL. If FALSE is returned the check is considered to have failed. Note - SECTION->data will be initialised at this point. */ - bool (* check_sec) (eu_checksec_data * DATA, - eu_checksec_section * SECTION); + bool (* check_sec) (annocheck_data * DATA, + annocheck_section * SECTION); /* Called before checking a segment. Can be NULL. If NULL, all segments are ignored. If FALSE is returned the segment is not processed any further. Note - called even if there are sections in the file. The SEG->DATA field may not have beeen initialised. */ - bool (* interesting_seg) (eu_checksec_data * DATA, - eu_checksec_segment * SEG); + bool (* interesting_seg) (annocheck_data * DATA, + annocheck_segment * SEG); /* Called to check a segment. If interesting_seg is not NULL, then this field cannot be NULL. If FALSE is returned the check is considered to have failed. the SEG->DATA field will have been initialised. */ - bool (* check_seg) (eu_checksec_data * DATA, - eu_checksec_segment * SEG); + bool (* check_seg) (annocheck_data * DATA, + annocheck_segment * SEG); /* Called at the end of checking a file. Can be NULL. Returns a success/fail status for the entire scan. */ - bool (* finish) (eu_checksec_data * DATA); + bool (* finish) (annocheck_data * DATA); /* Called to allow the callback a chance to handle its own command line arguments. Can be NULL. */ @@ -160,8 +160,8 @@ typedef struct checker #undef PTR /* Type for the ELF note walker. */ -typedef bool (* note_walker) (eu_checksec_data * DATA, - eu_checksec_section * SEC, +typedef bool (* note_walker) (annocheck_data * DATA, + annocheck_section * SEC, GElf_Nhdr * NOTE, size_t NAME_OFFSET, size_t DESC_OFFSET, @@ -171,27 +171,27 @@ typedef bool (* note_walker) (eu_checksec_data * DATA, Stops if FUNC returns FALSE. Passes PTR to FUNC along with a pointer to the note and the offsets to the name and desc data fields. Returns FALSE if it could not walk the notes. */ -extern bool eu_checksec_walk_notes (eu_checksec_data * DATA, eu_checksec_section * SEC, note_walker FUNC, void * PTR); +extern bool annocheck_walk_notes (annocheck_data * DATA, annocheck_section * SEC, note_walker FUNC, void * PTR); /* Type for the DWARF DIE walker. */ -typedef bool (* dwarf_walker) (eu_checksec_data * DATA, Dwarf * DWARF, Dwarf_Die * DIE, void * PTR); +typedef bool (* dwarf_walker) (annocheck_data * DATA, Dwarf * DWARF, Dwarf_Die * DIE, void * PTR); /* Walks over the DWARF DIEs in DATA, applying FUNC to each. Stops if FUNC returns FALSE. Passes PTR to FUNC along with a pointer to the DIE. Returns FALSE if it could not walk the debug information. */ -extern bool eu_checksec_walk_dwarf (eu_checksec_data * DATA, dwarf_walker FUNC, void * PTR); +extern bool annocheck_walk_dwarf (annocheck_data * DATA, dwarf_walker FUNC, void * PTR); /* Called to register a checker. Returns FALSE if the checker could not be registered. Can be called from static constructors. The MAJOR version number is used to verify that the checker is compatible with the framework. */ -extern bool eu_checksec_add_checker (struct checker * CHECKER, uint MAJOR); +extern bool annocheck_add_checker (struct checker * CHECKER, uint MAJOR); /* Return the name of a symbol most appropriate for address START..END. Returns NULL if no symbol could be found. */ -extern const char * eu_checksec_find_symbol_for_address_range - (eu_checksec_data * DATA, eu_checksec_section * SEC, ulong START, ulong ADDR, bool PREFER_FUNC); +extern const char * annocheck_find_symbol_for_address_range + (annocheck_data * DATA, annocheck_section * SEC, ulong START, ulong ADDR, bool PREFER_FUNC); /* An enum controlling the behaviour of the einfo function: */ typedef enum einfo_type @@ -221,4 +221,4 @@ extern ulong verbosity; extern uint major_version; extern uint minor_version; -#endif /* __EU_CHECKSEC_H__ */ +#endif /* __ANNOCHECK_H__ */ diff --git a/annocheck/built-by.c b/annocheck/built-by.c index 30a36ff..b638dd1 100644 --- a/annocheck/built-by.c +++ b/annocheck/built-by.c @@ -26,14 +26,14 @@ static bool found_builder; static bool all = false; static void -builtby_start (eu_checksec_data * data) +builtby_start (annocheck_data * data) { found_builder = false; } static bool -builtby_interesting_sec (eu_checksec_data * data, - eu_checksec_section * sec) +builtby_interesting_sec (annocheck_data * data, + annocheck_section * sec) { if (disabled) return false; @@ -67,8 +67,8 @@ found (const char * source, const char * filename, const char * tool) } static bool -builtby_note_walker (eu_checksec_data * data, - eu_checksec_section * sec, +builtby_note_walker (annocheck_data * data, + annocheck_section * sec, GElf_Nhdr * note, size_t name_offset, size_t data_offset, @@ -95,14 +95,14 @@ builtby_note_walker (eu_checksec_data * data, } static bool -builtby_check_sec (eu_checksec_data * data, - eu_checksec_section * sec) +builtby_check_sec (annocheck_data * data, + annocheck_section * sec) { if (streq (sec->secname, ".comment")) return found (".comment section", data->filename, (const char *) sec->data->d_buf); if (streq (sec->secname, GNU_BUILD_ATTRS_SECTION_NAME)) - return eu_checksec_walk_notes (data, sec, builtby_note_walker, (void *) data->filename); + return annocheck_walk_notes (data, sec, builtby_note_walker, (void *) data->filename); return true; /* Allow the search to continue. */ } @@ -110,7 +110,7 @@ builtby_check_sec (eu_checksec_data * data, /* Look for DW_AT_producer attributes. */ static bool -builtby_dwarf_walker (eu_checksec_data * data, Dwarf * dwarf, Dwarf_Die * die, void * ptr) +builtby_dwarf_walker (annocheck_data * data, Dwarf * dwarf, Dwarf_Die * die, void * ptr) { Dwarf_Attribute attr; const char * string; @@ -127,7 +127,7 @@ builtby_dwarf_walker (eu_checksec_data * data, Dwarf * dwarf, Dwarf_Die * die, v } static bool -builtby_finish (eu_checksec_data * data) +builtby_finish (annocheck_data * data) { if (disabled) return true; @@ -135,7 +135,7 @@ builtby_finish (eu_checksec_data * data) if (found_builder && ! all) return true; - (void) eu_checksec_walk_dwarf (data, builtby_dwarf_walker, NULL); + (void) annocheck_walk_dwarf (data, builtby_dwarf_walker, NULL); if (! found_builder) einfo (INFO, "%s: could not determine builder", data->filename); @@ -241,6 +241,6 @@ struct checker builtby_checker = static __attribute__((constructor)) void builtby_register_checker (void) { - if (! eu_checksec_add_checker (& builtby_checker, major_version)) + if (! annocheck_add_checker (& builtby_checker, major_version)) disabled = true; } diff --git a/annocheck/hardened.c b/annocheck/hardened.c index a8c140d..b785534 100644 --- a/annocheck/hardened.c +++ b/annocheck/hardened.c @@ -53,7 +53,7 @@ typedef struct test bool enabled; /* If false then do not run this test. */ enum test_result result; /* Initialised in start(), checked in finish(). */ const char * name; /* Also used as part of the command line option to disable the test. */ - void (* show_result)(eu_checksec_data *, enum test_result); + void (* show_result)(annocheck_data *, enum test_result); const char * description;/* Used in the --help output to describe the test. */ } test; @@ -80,23 +80,23 @@ enum test_index TEST_MAX }; -static void show_BIND_NOW (eu_checksec_data *, enum test_result); -static void show_CF_PROTECTION (eu_checksec_data *, enum test_result); -static void show_DYNAMIC_SEGMENT (eu_checksec_data *, enum test_result); -static void show_FORTIFY (eu_checksec_data *, enum test_result); -static void show_GLIBCXX_ASSERTIONS (eu_checksec_data *, enum test_result); -static void show_GNU_RELRO (eu_checksec_data *, enum test_result); -static void show_GNU_STACK (eu_checksec_data *, enum test_result); -static void show_OPTIMIZATION (eu_checksec_data *, enum test_result); -static void show_PIC (eu_checksec_data *, enum test_result); -static void show_RUN_PATH (eu_checksec_data *, enum test_result); -static void show_RWX_SEG (eu_checksec_data *, enum test_result); -static void show_STACK_CLASH (eu_checksec_data *, enum test_result); -static void show_STACK_PROT (eu_checksec_data *, enum test_result); -static void show_STACK_REALIGN (eu_checksec_data *, enum test_result); -static void show_TEXTREL (eu_checksec_data *, enum test_result); -static void show_THREADS (eu_checksec_data *, enum test_result); -static void show_WRITEABLE_GOT (eu_checksec_data *, enum test_result); +static void show_BIND_NOW (annocheck_data *, enum test_result); +static void show_CF_PROTECTION (annocheck_data *, enum test_result); +static void show_DYNAMIC_SEGMENT (annocheck_data *, enum test_result); +static void show_FORTIFY (annocheck_data *, enum test_result); +static void show_GLIBCXX_ASSERTIONS (annocheck_data *, enum test_result); +static void show_GNU_RELRO (annocheck_data *, enum test_result); +static void show_GNU_STACK (annocheck_data *, enum test_result); +static void show_OPTIMIZATION (annocheck_data *, enum test_result); +static void show_PIC (annocheck_data *, enum test_result); +static void show_RUN_PATH (annocheck_data *, enum test_result); +static void show_RWX_SEG (annocheck_data *, enum test_result); +static void show_STACK_CLASH (annocheck_data *, enum test_result); +static void show_STACK_PROT (annocheck_data *, enum test_result); +static void show_STACK_REALIGN (annocheck_data *, enum test_result); +static void show_TEXTREL (annocheck_data *, enum test_result); +static void show_THREADS (annocheck_data *, enum test_result); +static void show_WRITEABLE_GOT (annocheck_data *, enum test_result); #define TEST(name,upper,description) \ [ TEST_##upper ] = { true, 0, #name, show_ ## upper, description } @@ -126,7 +126,7 @@ static test tests [TEST_MAX] = static void -start (eu_checksec_data * data) +start (annocheck_data * data) { /* (Re) Set the results for the tests. */ int i; @@ -158,8 +158,8 @@ start (eu_checksec_data * data) } static bool -interesting_sec (eu_checksec_data * data, - eu_checksec_section * sec) +interesting_sec (annocheck_data * data, + annocheck_section * sec) { if (disabled) return false; @@ -218,13 +218,13 @@ typedef struct hardened_note_data } hardened_note_data; static const char * -get_component_name (eu_checksec_data * data, - eu_checksec_section * sec, +get_component_name (annocheck_data * data, + annocheck_section * sec, hardened_note_data * note_data, bool prefer_func_symbol) { static char buffer[256]; - const char * sym = eu_checksec_find_symbol_for_address_range (data, sec, note_data->start, note_data->end, prefer_func_symbol); + const char * sym = annocheck_find_symbol_for_address_range (data, sec, note_data->start, note_data->end, prefer_func_symbol); if (sym == NULL) sprintf (buffer, "addr range: %#lx..%#lx", note_data->start, note_data->end); @@ -278,19 +278,22 @@ skip_check (enum test_index check ATTRIBUTE_UNUSED, const char * component_name) } static bool -walk_notes (eu_checksec_data * data, - eu_checksec_section * sec, - GElf_Nhdr * note, - size_t name_offset, - size_t data_offset, - void * ptr) +walk_notes (annocheck_data * data, + annocheck_section * sec, + GElf_Nhdr * note, + size_t name_offset, + size_t data_offset, + void * ptr) { bool prefer_func_name; hardened_note_data * note_data; if (note->n_type != NT_GNU_BUILD_ATTRIBUTE_OPEN && note->n_type != NT_GNU_BUILD_ATTRIBUTE_FUNC) - return true; + { + einfo (FAIL, "Unrecognised annobin note type %d", note->n_type); + return false; + } prefer_func_name = note->n_type == NT_GNU_BUILD_ATTRIBUTE_FUNC; note_data = (hardened_note_data *) ptr; @@ -328,7 +331,10 @@ walk_notes (eu_checksec_data * data, end = descdata[4] | (descdata[5] << 8) | (descdata[6] << 16) | (descdata[7] << 24); } else - return false; + { + einfo (FAIL, "Corrupt annobin note, desc size: %x", note->n_descsz); + return false; + } if (note->n_type == NT_GNU_BUILD_ATTRIBUTE_OPEN) { @@ -342,7 +348,7 @@ walk_notes (eu_checksec_data * data, if (! ignore_gaps) { - const char * sym = eu_checksec_find_symbol_for_address_range (data, sec, + const char * sym = annocheck_find_symbol_for_address_range (data, sec, fake_note.start, fake_note.end, prefer_func_name); /* Note - we ignore gaps at the start and end of the file. These are @@ -366,10 +372,13 @@ walk_notes (eu_checksec_data * data, } if (note->n_namesz < 3) - return false; + { + einfo (FAIL, "Corrupt annobin note, name size: %x", note->n_namesz); + return false; + } - /* We skip notes for empty ranges. */ - if (note_data->start == note_data->end) + /* We skip notes for empty ranges unless we are dealing with unrelocated object files. */ + if (e_type != ET_REL && note_data->start == note_data->end) return true; const char * namedata = sec->data->d_buf + name_offset; @@ -707,8 +716,8 @@ walk_notes (eu_checksec_data * data, } static bool -check_note_section (eu_checksec_data * data, - eu_checksec_section * sec) +check_note_section (annocheck_data * data, + annocheck_section * sec) { if (streq (sec->secname, GNU_BUILD_ATTRS_SECTION_NAME)) { @@ -718,15 +727,15 @@ check_note_section (eu_checksec_data * data, hard_data.end = 0; hard_data.prev_end = 0; - return eu_checksec_walk_notes (data, sec, walk_notes, (void *) & hard_data); + return annocheck_walk_notes (data, sec, walk_notes, (void *) & hard_data); } return true; } static bool -check_string_section (eu_checksec_data * data, - eu_checksec_section * sec) +check_string_section (annocheck_data * data, + annocheck_section * sec) { /* Check the string table to see if it contains "__pthread_register_cancel". This is not as accurate as checking for a function symbol with this name, @@ -754,8 +763,8 @@ not_rooted_at_usr (const char * str) } static bool -check_dynamic_section (eu_checksec_data * data, - eu_checksec_section * sec) +check_dynamic_section (annocheck_data * data, + annocheck_section * sec) { size_t num_entries = sec->shdr.sh_size / sec->shdr.sh_entsize; @@ -787,8 +796,8 @@ check_dynamic_section (eu_checksec_data * data, } static bool -check_sec (eu_checksec_data * data, - eu_checksec_section * sec) +check_sec (annocheck_data * data, + annocheck_section * sec) { /* Note - the types checked here should correspond to the types selected in interesting_sec(). */ @@ -804,8 +813,8 @@ check_sec (eu_checksec_data * data, } static bool -interesting_seg (eu_checksec_data * data, - eu_checksec_segment * seg) +interesting_seg (annocheck_data * data, + annocheck_segment * seg) { if (disabled) return false; @@ -839,33 +848,33 @@ interesting_seg (eu_checksec_data * data, } static void -fail (eu_checksec_data * data, const char * message) +fail (annocheck_data * data, const char * message) { einfo (INFO, "%s: FAIL: %s", data->filename, message); ++ num_fails; } static void -maybe (eu_checksec_data * data, const char * message) +maybe (annocheck_data * data, const char * message) { einfo (INFO, "%s: MAYB: %s", data->filename, message); ++ num_maybes; } static void -pass (eu_checksec_data * data, const char * message) +pass (annocheck_data * data, const char * message) { einfo (VERBOSE, "%s: pass: %s", data->filename, message); } static void -ice (eu_checksec_data * data, const char * message) +ice (annocheck_data * data, const char * message) { einfo (INFO, "%s: internal error: %s", data->filename, message); } static void -show_BIND_NOW (eu_checksec_data * data, enum test_result result) +show_BIND_NOW (annocheck_data * data, enum test_result result) { /* Only executables need to have their binding checked. */ if (e_type != ET_EXEC) @@ -880,7 +889,7 @@ show_BIND_NOW (eu_checksec_data * data, enum test_result result) } static void -show_DYNAMIC_SEGMENT (eu_checksec_data * data, enum test_result result) +show_DYNAMIC_SEGMENT (annocheck_data * data, enum test_result result) { /* Relocateable object files do not have dynamic segments. */ if (e_type == ET_REL) @@ -895,7 +904,7 @@ show_DYNAMIC_SEGMENT (eu_checksec_data * data, enum test_result result) } static void -show_GNU_RELRO (eu_checksec_data * data, enum test_result result) +show_GNU_RELRO (annocheck_data * data, enum test_result result) { /* Relocateable object files are not yet linked. */ if (e_type == ET_REL) @@ -910,7 +919,7 @@ show_GNU_RELRO (eu_checksec_data * data, enum test_result result) } static void -show_GNU_STACK (eu_checksec_data * data, enum test_result result) +show_GNU_STACK (annocheck_data * data, enum test_result result) { /* Relocateable object files do not have a stack. */ if (e_type == ET_REL) @@ -925,7 +934,7 @@ show_GNU_STACK (eu_checksec_data * data, enum test_result result) } static void -show_RWX_SEG (eu_checksec_data * data, enum test_result result) +show_RWX_SEG (annocheck_data * data, enum test_result result) { /* Relocateable object files do not have segments. */ if (e_type == ET_REL) @@ -940,7 +949,7 @@ show_RWX_SEG (eu_checksec_data * data, enum test_result result) } static void -show_PIC (eu_checksec_data * data, enum test_result result) +show_PIC (annocheck_data * data, enum test_result result) { switch (result) { @@ -952,7 +961,7 @@ show_PIC (eu_checksec_data * data, enum test_result result) } static void -show_STACK_PROT (eu_checksec_data * data, enum test_result result) +show_STACK_PROT (annocheck_data * data, enum test_result result) { switch (result) { @@ -964,7 +973,7 @@ show_STACK_PROT (eu_checksec_data * data, enum test_result result) } static void -show_STACK_CLASH (eu_checksec_data * data, enum test_result result) +show_STACK_CLASH (annocheck_data * data, enum test_result result) { /* The ARM does not have stack clash protection support. */ if (e_machine == EM_ARM) @@ -989,7 +998,7 @@ show_STACK_CLASH (eu_checksec_data * data, enum test_result result) } static void -show_TEXTREL (eu_checksec_data * data, enum test_result result) +show_TEXTREL (annocheck_data * data, enum test_result result) { /* Relocateable object files can have text relocations. */ if (e_type == ET_REL) @@ -1004,7 +1013,7 @@ show_TEXTREL (eu_checksec_data * data, enum test_result result) } static void -show_FORTIFY (eu_checksec_data * data, enum test_result result) +show_FORTIFY (annocheck_data * data, enum test_result result) { switch (result) { @@ -1017,7 +1026,7 @@ show_FORTIFY (eu_checksec_data * data, enum test_result result) } static void -show_CF_PROTECTION (eu_checksec_data * data, enum test_result result) +show_CF_PROTECTION (annocheck_data * data, enum test_result result) { if (e_machine != EM_386 && e_machine != EM_X86_64) return; @@ -1041,7 +1050,7 @@ show_CF_PROTECTION (eu_checksec_data * data, enum test_result result) } static void -show_GLIBCXX_ASSERTIONS (eu_checksec_data * data, enum test_result result) +show_GLIBCXX_ASSERTIONS (annocheck_data * data, enum test_result result) { switch (result) { @@ -1053,7 +1062,7 @@ show_GLIBCXX_ASSERTIONS (eu_checksec_data * data, enum test_result result) } static void -show_STACK_REALIGN (eu_checksec_data * data, enum test_result result) +show_STACK_REALIGN (annocheck_data * data, enum test_result result) { if (e_machine != EM_386) return; @@ -1068,7 +1077,7 @@ show_STACK_REALIGN (eu_checksec_data * data, enum test_result result) } static void -show_RUN_PATH (eu_checksec_data * data, enum test_result result) +show_RUN_PATH (annocheck_data * data, enum test_result result) { /* Relocateable object files do not need a runtime path. */ if (e_type == ET_REL) @@ -1083,7 +1092,7 @@ show_RUN_PATH (eu_checksec_data * data, enum test_result result) } static void -show_THREADS (eu_checksec_data * data, enum test_result result) +show_THREADS (annocheck_data * data, enum test_result result) { switch (result) { @@ -1094,7 +1103,7 @@ show_THREADS (eu_checksec_data * data, enum test_result result) } static void -show_WRITEABLE_GOT (eu_checksec_data * data, enum test_result result) +show_WRITEABLE_GOT (annocheck_data * data, enum test_result result) { /* Relocateable object files do not have a GOT. */ if (e_type == ET_REL) @@ -1109,7 +1118,7 @@ show_WRITEABLE_GOT (eu_checksec_data * data, enum test_result result) } static void -show_OPTIMIZATION (eu_checksec_data * data, enum test_result result) +show_OPTIMIZATION (annocheck_data * data, enum test_result result) { switch (result) { @@ -1121,7 +1130,7 @@ show_OPTIMIZATION (eu_checksec_data * data, enum test_result result) } static bool -finish (eu_checksec_data * data) +finish (annocheck_data * data) { if (disabled || debuginfo_file) return true; @@ -1242,6 +1251,6 @@ struct checker hardened_checker = static __attribute__((constructor)) void register_checker (void) { - if (! eu_checksec_add_checker (& hardened_checker, major_version)) + if (! annocheck_add_checker (& hardened_checker, major_version)) disabled = true; } diff --git a/plugin/aarch64.annobin.cc b/plugin/aarch64.annobin.cc index c5ff3a9..3467cef 100644 --- a/plugin/aarch64.annobin.cc +++ b/plugin/aarch64.annobin.cc @@ -43,13 +43,13 @@ annobin_record_global_target_notes (void) } void -annobin_target_specific_function_notes (const char * aname, const char * aname_end) +annobin_target_specific_function_notes (const char * aname, const char * aname_end, bool force) { - if (saved_tls_dialect == aarch64_tls_dialect) + if (!force && saved_tls_dialect == aarch64_tls_dialect) return; - annobin_inform (1, "TLS dialect has changed from %d to %d for %s", - saved_tls_dialect, aarch64_tls_dialect, current_function_name ()); + annobin_inform (1, "recording TLS dialect of %d for %s", + aarch64_tls_dialect, current_function_name ()); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, aarch64_tls_dialect, "numeric: ABI: TLS dialect", aname, aname_end, diff --git a/plugin/annobin.cc b/plugin/annobin.cc index 00a9135..fe07260 100644 --- a/plugin/annobin.cc +++ b/plugin/annobin.cc @@ -178,10 +178,8 @@ annobin_inform (unsigned level, const char * format, ...) fflush (stdout); fprintf (stderr, "annobin: "); - if (annobin_current_filename == NULL) - init_annobin_current_filename (); - if (annobin_current_filename) - fprintf (stderr, "%s: ", annobin_current_filename); + if (main_input_filename) + fprintf (stderr, "%s: ", main_input_filename); va_start (args, format); vfprintf (stderr, format, args); va_end (args); @@ -703,64 +701,34 @@ function_asm_name (void) return id; } -/* Create any notes specific to the current function. */ +static const char * saved_end_sym; static void -annobin_create_function_notes (void * gcc_data, void * user_data) +annobin_emit_function_notes (const char * func_name, + const char * start_sym, + const char * end_sym, + bool force) { - const char * func_name; - const char * asm_name; - const char * start_sym; - const char * end_sym; - const char * saved_start_sym; - const char * saved_end_sym; - unsigned int count; + unsigned int count = annobin_note_count; - if (! annobin_enable_static_notes || asm_out_file == NULL) - return; - - func_name = current_function_name (); - asm_name = function_asm_name (); - - if (func_name == NULL) + if (force) { - func_name = asm_name; - - if (func_name == NULL) - { - /* Can this happen ? */ - annobin_inform (0, "ICE: function name not available"); - return; - } + /* XXX FIXME - generate the other global style notes as well. */ } - if (asm_name == NULL) - asm_name = func_name; - - /* We use our own function start and end symbols so that they will - not interfere with the program proper. In particular if we use - the function name symbol ourselves then we can cause problems - when the linker attempts to relocs against it and finds that it - has both PC relative and abolsute relocs. - - We try our best to ensure that the new symbols will not clash - with any other symbols in the program. */ - saved_start_sym = start_sym = concat (ANNOBIN_SYMBOL_PREFIX, asm_name, "_start", NULL); - saved_end_sym = end_sym = concat (ANNOBIN_SYMBOL_PREFIX, asm_name, "_end", NULL); - - count = annobin_note_count; - - annobin_target_specific_function_notes (start_sym, end_sym); + annobin_target_specific_function_notes (start_sym, end_sym, force); /* If one or more notes were generated by the target specific function then we no longer need to include the start/end symbols in any futher notes that we gebenerate. */ if (annobin_note_count > count) start_sym = end_sym = NULL; - if (global_stack_prot_option != flag_stack_protect && flag_stack_protect != -1) + if (flag_stack_protect != -1 + && (force + || global_stack_prot_option != flag_stack_protect)) { - annobin_inform (1, "Recording change in stack protection status for %s (from %d to %d)", - func_name, global_stack_prot_option, flag_stack_protect); + annobin_inform (1, "Recording stack protection status of %d for %s", + flag_stack_protect, func_name); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, flag_stack_protect, "numeric: -fstack-protector status", @@ -771,48 +739,52 @@ annobin_create_function_notes (void * gcc_data, void * user_data) } #ifdef flag_stack_clash_protection - if (global_stack_clash_option != flag_stack_clash_protection) + if (force + || global_stack_clash_option != flag_stack_clash_protection) { - annobin_inform (1, "Recording change in stack clash protection status for %s (from %d to %d)", - func_name, global_stack_clash_option, flag_stack_clash_protection); + annobin_inform (1, "Recording stack clash protection status of %d for %s", + flag_stack_clash_protection, func_name); record_stack_clash_note (start_sym, end_sym, FUNC); - start_sym = end_sym = NULL; } #endif #ifdef flag_cf_protection - if (global_cf_option != flag_cf_protection) + if (force + || global_cf_option != flag_cf_protection) { - annobin_inform (1, "Recording change in control flow protection status for %s (from %d to %d)", - func_name, global_cf_option, flag_cf_protection); + annobin_inform (1, "Recording control flow protection status of %d for %s", + flag_cf_protection, func_name); record_cf_protection_note (start_sym, end_sym, FUNC); - start_sym = end_sym = NULL; } #endif - if (global_pic_option != compute_pic_option ()) + if (force + || global_pic_option != compute_pic_option ()) { - annobin_inform (1, "Recording change in PIC status for %s", func_name); + annobin_inform (1, "Recording PIC status of %s", func_name); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, compute_pic_option (), "numeric: pic type", start_sym, end_sym, FUNC); start_sym = end_sym = NULL; } - if (global_GOWall_options != compute_GOWall_options ()) + if (force + || global_GOWall_options != compute_GOWall_options ()) { record_GOW_settings (compute_GOWall_options (), true, func_name, start_sym, end_sym); start_sym = end_sym = NULL; } - if (global_short_enums != flag_short_enums && flag_short_enums != -1) + if (flag_short_enums != -1 + && (force + || global_short_enums != flag_short_enums)) { - annobin_inform (1, "Recording change in enum size for %s", func_name); + annobin_inform (1, "Recording enum size for %s", func_name); annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, flag_short_enums, flag_short_enums ? "bool: short-enums: on" : "bool: short-enums: off", start_sym, end_sym, FUNC); @@ -838,27 +810,111 @@ annobin_create_function_notes (void * gcc_data, void * user_data) if ((unsigned long) current_function_static_stack_size > annobin_max_stack_size) annobin_max_stack_size = current_function_static_stack_size; } +} - if (annobin_note_count > count) +#if 0 +/* These includes are needed in order to be able to access crtl-> */ +#include "rtl.h" +#include "memmodel.h" +#include "emit-rtl.h" +#endif + +/* Create any notes specific to the current function. */ + +static void +annobin_create_function_notes (void * gcc_data, void * user_data) +{ + const char * func_section; + const char * func_name; + const char * asm_name; + const char * start_sym; + const char * end_sym; + bool force; + unsigned int count; + + if (saved_end_sym != NULL) + annobin_inform (0, "XXX ICE: end sym %s not NULL\n", saved_end_sym); + + if (! annobin_enable_static_notes || asm_out_file == NULL) + return; + + func_section = DECL_SECTION_NAME (current_function_decl); + if (func_section == NULL) { - const char * dsn = DECL_SECTION_NAME (current_function_decl); + section * sec = function_section (current_function_decl); - /* If we generated any notes then we must make sure - that the symbols have been emitted as well. */ - if (dsn == NULL) + if (sec != NULL) { - fprintf (asm_out_file, "\t.equiv %s, %s\n", saved_start_sym, asm_name); - fprintf (asm_out_file, "\t.hidden %s\n", saved_start_sym); - fprintf (asm_out_file, "\t.hidden %s\n", saved_end_sym); - fprintf (asm_out_file, "%s:\n", saved_end_sym); + if (sec->common.flags & SECTION_NAMED) + func_section = sec->named.name; + } + } + + func_name = current_function_name (); + asm_name = function_asm_name (); + + if (func_name == NULL) + { + func_name = asm_name; + + if (func_name == NULL) + { + /* Can this happen ? */ + annobin_inform (0, "ICE: function name not available"); + return; + } + } + + if (asm_name == NULL) + asm_name = func_name; + + if (func_section == NULL && flag_function_sections) + func_section = concat (".text.", func_name, NULL); /* FIXME: memory leak. */ + + /* If the function is going to be in its own section, then we do not know + where it will end up in memory. In particular we cannot rely upon it + being included in the memory range covered by the global notes. So for + such functions we always generate a full range of notes. + Likewise if the compiler is generating cold code, then we need to emit + notes for the cold section as well. */ + force = func_section != NULL; + + /* We use our own function start and end symbols so that they will + not interfere with the program proper. In particular if we use + the function name symbol ourselves then we can cause problems + when the linker attempts to relocs against it and finds that it + has both PC relative and abolsute relocs. + + We try our best to ensure that the new symbols will not clash + with any other symbols in the program. */ + start_sym = concat (ANNOBIN_SYMBOL_PREFIX, asm_name, ".start", NULL); + end_sym = concat (ANNOBIN_SYMBOL_PREFIX, asm_name, ".end", NULL); + + count = annobin_note_count; + annobin_emit_function_notes (func_name, start_sym, end_sym, force); + + if (annobin_note_count > count) + { + /* If we generated any notes then we must make sure that the start + symbol has been emitted as well. The end symbols will be emitted + by annobin_create_function_end_symbol, once the body of the function + has been written to the assembler file. + + Note we cannot just use ".equiv start_sym, asm_name", as the + assembler symbol might have a special type, eg ifunc, and this + would be inherited by our symbol. */ + if (func_section == NULL) + { + fprintf (asm_out_file, "\t.type %s, STT_NOTYPE\n", start_sym); + fprintf (asm_out_file, "\t.hidden %s\n", start_sym); + fprintf (asm_out_file, "%s:\n", start_sym); } else { - /* The push/pop is probably not necessary, but let's be paranoid. */ - fprintf (asm_out_file, "\t.pushsection %s\n", dsn); - fprintf (asm_out_file, "\t.equiv %s, %s\n", saved_start_sym, asm_name); - fprintf (asm_out_file, "\t.type %s STT_NOTYPE\n", saved_start_sym); - fprintf (asm_out_file, "%s:\n", saved_end_sym); + fprintf (asm_out_file, "\t.pushsection %s, \"ax\"\n", func_section); + fprintf (asm_out_file, "\t.type %s, STT_NOTYPE\n", start_sym); + fprintf (asm_out_file, "\t.hidden %s\n", start_sym); + fprintf (asm_out_file, "%s:\n", start_sym); fprintf (asm_out_file, "\t.popsection\n"); /* If the function is in a linkonce section then it is possible that @@ -875,20 +931,96 @@ annobin_create_function_notes (void * gcc_data, void * user_data) comment in annobin_output_note() for more details. FIXME - Do we need to worry about COMDAT code sections ? */ - if (strstr (dsn, ".gnu.linkonce.")) + if (strstr (func_section, ".gnu.linkonce.")) { fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME); - fprintf (asm_out_file, "\t.weak %s\n", saved_start_sym); - fprintf (asm_out_file, "\t.hidden %s\n", saved_start_sym); - fprintf (asm_out_file, "\t.weak %s\n", saved_end_sym); - fprintf (asm_out_file, "\t.hidden %s\n", saved_end_sym); + fprintf (asm_out_file, "\t.weak %s\n", start_sym); + fprintf (asm_out_file, "\t.hidden %s\n", start_sym); + fprintf (asm_out_file, "\t.weak %s\n", end_sym); + fprintf (asm_out_file, "\t.hidden %s\n", end_sym); fprintf (asm_out_file, "\t.popsection\n"); } } + + saved_end_sym = end_sym; } + else + { + free ((void *) end_sym); + } + + free ((void *) start_sym); +#if 0 + annobin_inform (0, "START: bb %d label %p", crtl->has_bb_partition, crtl->subsections.cold_section_label); +#endif +} + + +static void +annobin_create_function_end_symbol (void * gcc_data, void * user_data) +{ + if (! annobin_enable_static_notes || asm_out_file == NULL) + return; + +#if 0 + annobin_inform (0, "END: bb %d label %p", crtl->has_bb_partition, crtl->subsections.cold_section_label); +#endif + if (saved_end_sym) + { + const char * dsn = DECL_SECTION_NAME (current_function_decl); + + if (dsn) + { + /* The push/pop are probably not necessary, but let's be paranoid. */ + fprintf (asm_out_file, "\t.pushsection %s\n", dsn); + fprintf (asm_out_file, "\t.hidden %s\n", saved_end_sym); + fprintf (asm_out_file, "%s:\n", saved_end_sym); + fprintf (asm_out_file, "\t.popsection\n"); + } + else + { + fprintf (asm_out_file, "\t.hidden %s\n", saved_end_sym); + fprintf (asm_out_file, "%s:\n", saved_end_sym); + } - free ((void *) saved_start_sym); - free ((void *) saved_end_sym); + free ((void *) saved_end_sym); + saved_end_sym = NULL; + } +#if 0 + switch_to_section (unlikely_text_section ()); + fprintf (asm_out_file, ".xxx\n"); + + /* Determine if this function has a cold section. + Note - we cannot use gcc's cold_function_name variable as this + is not kept in sync with the current function. */ + + if (crtl->has_bb_partition) + { + /* If the function has a cold portion it will be emitted into a + separate section. So we must create a whole set of notes for + them too. */ + + const char * cold_name = current_function_name (); + const char * cold_start_sym; + const char * cold_end_sym; + + annobin_inform (0, "func sec cold name %s\n", cold_name); + + cold_start_sym = concat (ANNOBIN_SYMBOL_PREFIX, ".cold.", cold_name, ".start", NULL); + cold_end_sym = concat (ANNOBIN_SYMBOL_PREFIX, ".cold.", cold_name, ".end", NULL); + + switch_to_section (unlikely_text_section ()); + fprintf (asm_out_file, "\t.hidden %s\n", cold_start_sym); + fprintf (asm_out_file, "\t.equiv %s, %s\n", cold_start_sym, cold_name); + fprintf (asm_out_file, "\t.hidden %s\n", cold_end_sym); + fprintf (asm_out_file, "%s:\n", cold_end_sym); + + annobin_emit_function_notes (cold_name, cold_start_sym, cold_end_sym, true); + + free ((void *) cold_start_sym); + free ((void *) cold_end_sym); + } +#endif } static void @@ -1264,7 +1396,7 @@ plugin_init (struct plugin_name_args * plugin_info, if (strcmp (version->basever, gcc_version.basever)) { annobin_inform (0, _("Error: plugin built for compiler version (%s) but run with compiler version (%s)"), - version->basever, gcc_version.basever); + gcc_version.basever, version->basever); fail = true; } @@ -1373,10 +1505,15 @@ plugin_init (struct plugin_name_args * plugin_info, NULL); register_callback ("annobin: Generate per-function annotations", - PLUGIN_ALL_PASSES_END, + PLUGIN_ALL_PASSES_START, annobin_create_function_notes, NULL); + register_callback ("annobin: Register per-function end symbol", + PLUGIN_ALL_PASSES_END, + annobin_create_function_end_symbol, + NULL); + register_callback ("annobin: Generate final annotations", PLUGIN_FINISH_UNIT, annobin_create_loader_notes, diff --git a/plugin/annobin.h b/plugin/annobin.h index 16e9d67..8f48e8b 100644 --- a/plugin/annobin.h +++ b/plugin/annobin.h @@ -87,12 +87,14 @@ extern void annobin_save_target_specific_information (void); notes in the .gnu.build.attributes section. */ extern void annobin_record_global_target_notes (void); -/* Called during PLUGIN_ALL_PASSES_END. +/* Called during PLUGIN_ALL_PASSES_START. Should produce notes specific to the function just compiled. Should only produce notes for the static tools, ie notes in the .gnu.build.attributes section. - Arguments are the start and end symbols for the function. */ -extern void annobin_target_specific_function_notes (const char *, const char *); + Arguments are the start and end symbols for the function, + and a boolean indicating if the notes should be generated, + even if nothing has changed. */ +extern void annobin_target_specific_function_notes (const char *, const char *, bool); /* Called during PLUGIN_FINISH_UNIT. Should only produce notes for the dynamic loader, ie diff --git a/plugin/dummy.annobin.cc b/plugin/dummy.annobin.cc index c267fc4..adc3c4c 100644 --- a/plugin/dummy.annobin.cc +++ b/plugin/dummy.annobin.cc @@ -20,7 +20,7 @@ annobin_save_target_specific_information - Called during plugin_init() annobin_target_start_symbol_bias - Called during plugin_init() annobin_record_global_target_notes - Called during PLUGIN_START_UNIT - annobin_target_specific_function_notes - Called during PLUGIN_ALL_PASSES_END + annobin_target_specific_function_notes - Called during PLUGIN_ALL_PASSES_START annobin_target_specific_loader_notes - Called during PLUGIN_FINISH_UNIT. */ signed int @@ -40,7 +40,7 @@ annobin_record_global_target_notes (void) } void -annobin_target_specific_function_notes (const char * aname, const char * aname_end) +annobin_target_specific_function_notes (const char * aname, const char * aname_end, bool force) { } diff --git a/plugin/powerpc.annobin.cc b/plugin/powerpc.annobin.cc index 2dafadf..4a662b5 100644 --- a/plugin/powerpc.annobin.cc +++ b/plugin/powerpc.annobin.cc @@ -48,13 +48,13 @@ annobin_record_global_target_notes (void) } void -annobin_target_specific_function_notes (const char * aname, const char * aname_end) +annobin_target_specific_function_notes (const char * aname, const char * aname_end, bool force) { - if (saved_tls_size == rs6000_tls_size) + if (!force && saved_tls_size == rs6000_tls_size) return; - annobin_inform (1, "TLS size has changed from %d to %d for %s", - saved_tls_size, rs6000_tls_size, aname); + annobin_inform (1, "Record TLS size of %d for %s", + rs6000_tls_size, aname); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, rs6000_tls_size, "numeric: ABI: TLS size", aname, aname_end, FUNC); diff --git a/plugin/x86_64.annobin.cc b/plugin/x86_64.annobin.cc index 6599d68..da16d21 100644 --- a/plugin/x86_64.annobin.cc +++ b/plugin/x86_64.annobin.cc @@ -117,12 +117,15 @@ annobin_record_global_target_notes (void) } void -annobin_target_specific_function_notes (const char * aname, const char * aname_end) +annobin_target_specific_function_notes (const char * aname, const char * aname_end, bool force) { - if ((unsigned long) ix86_isa_flags != global_x86_isa) + const char * func_name = aname; + + if (force + || (unsigned long) ix86_isa_flags != global_x86_isa) { - annobin_inform (1, "ISA value has changed from %lx to %lx for %s", - global_x86_isa, ix86_isa_flags, aname); + annobin_inform (1, "record ISA value of %lx for %s", + ix86_isa_flags, func_name); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, ix86_isa_flags, "numeric: ABI", aname, aname_end, FUNC); @@ -131,40 +134,38 @@ annobin_target_specific_function_notes (const char * aname, const char * aname_e min_x86_isa = ix86_isa_flags; if ((unsigned long) ix86_isa_flags > max_x86_isa) max_x86_isa = ix86_isa_flags; + + aname = aname_end = NULL; } - if (ix86_force_align_arg_pointer != global_stack_realign) + if (force + || ix86_force_align_arg_pointer != global_stack_realign) { char buffer [128]; unsigned len = sprintf (buffer, "GA%cstack_realign", ix86_force_align_arg_pointer ? BOOL_T : BOOL_F); + + annobin_inform (1, "Record function specific stack realign setting of %s for %s", + ix86_force_align_arg_pointer ? "false" : "true", func_name); annobin_output_static_note (buffer, len + 1, true, "bool: -mstackrealign status", aname, aname_end, FUNC); - annobin_inform (1, "Record function specific stack realign setting of %s for %s", - ix86_force_align_arg_pointer ? "false" : "true", aname); + aname = aname_end = NULL; } #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) + if (force + || (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 (1, "CET values have changed from %d:%d:%lx:%lx to %d:%d:%lx:%lx", - global_cet, global_set_switch, global_ibt, global_shstk, + annobin_inform (1, "recording CET value of %d:%d:%lx:%lx for %s", flag_cet, flag_cet_switch, (ix86_isa_flags2 & OPTION_MASK_ISA_IBT), - (ix86_isa_flags & OPTION_MASK_ISA_SHSTK)); + (ix86_isa_flags & OPTION_MASK_ISA_SHSTK) + func_name); record_cet_note (aname, aname_end, FUNC); + aname = aname_end = NULL; } #endif } diff --git a/tests/hardening-fail-test b/tests/hardening-fail-test index 2d56255..e58b5b1 100755 --- a/tests/hardening-fail-test +++ b/tests/hardening-fail-test @@ -20,48 +20,14 @@ OBJCOPY=objcopy PLUGIN=../plugin/.libs/annobin.so -$GCC -fplugin=$PLUGIN \ - -c \ - -fPIC \ - -Wall \ - -g \ - -fno-stack-protector \ - -fplugin-arg-annobin-stack-threshold=0x10 \ - $srcdir/hello.c - -$GCC -fplugin=$PLUGIN \ - -O3 \ - -c \ - -fPIC \ - -fno-stack-protector \ - -fplugin-arg-annobin-global-file-syms \ - $srcdir/hello2.c +OPTS="-fno-stack-protector -O1 -D_FORTIFY_SOURCE=1" $GCC -fplugin=$PLUGIN \ - -O2 \ -c \ - -fPIE \ - -g3 \ - -fstack-protector-strong \ - -D_FORTIFY_SOURCE=2 \ - -fplugin-arg-annobin-no-stack-size-notes \ - -grecord-gcc-switches \ - $srcdir/hello3.c \ - -$GCC -fplugin=$PLUGIN \ - -O2 \ - -fpic \ - -fstack-protector \ - -shared \ - $srcdir/hello_lib.c \ - -o libhello.so - -$GCC -fplugin=$PLUGIN \ - -L . -pie \ - -Wl,-z,now,-z,relro \ - hello.o hello2.o hello3.o -lhello -o hardening-fail-test.exe + $OPTS \ + $srcdir/hello.c $srcdir/hello2.c $srcdir/hello3.c $srcdir/hello_lib.c -# $OBJCOPY --merge-notes hardening-fail-test.exe hardening-fail-test-merged.exe +$GCC hello.o hello2.o hello3.o hello_lib.o -o hardening-fail-test.exe ../annocheck/annocheck hardening-fail-test.exe diff --git a/tests/unused_code.c b/tests/unused_code.c index bff5285..9db62cc 100644 --- a/tests/unused_code.c +++ b/tests/unused_code.c @@ -35,3 +35,45 @@ linkonce_func_1 (void) { return 26; } + +void * foo_ifunc (void) __asm__ ("food"); + +__asm__(".type foo, %gnu_indirect_function"); + +static float +foo_impl (float x) +{ + return x + 1; +} + +void * foo_ifunc (void) __attribute__((optimize("-O0"),__noinline__)); + +void * +foo_ifunc (void) +{ + asm volatile (".dc.l 0" ); + return foo_impl; +} + +extern int bar (int); +extern int baz (int) __attribute__((cold)); + +void hot (int) __attribute__((optimize("-O3"),__noinline__)); + +void +hot (int x) +{ + if (x) + bar (bar (5)); + else + baz (baz (baz (baz (12)))); +} + +void +hotter (int x) +{ + if (x) + bar (bar (7)); + else + baz (baz (baz (baz (13)))); +} -- 2.43.5