diff --git a/gold/script.cc b/gold/script.cc index d6aa7b250a4c6ecc5719d0ec99c6ddec5375eba7..4ecd3fc0dcf9280c2a3a86d298831cea1998b402 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -666,7 +666,7 @@ Lex::one_char_operator(char c1) } // Skip a C style comment. *PP points to just after the "/*". Return -// false if the comment did not end. +// false if the comment did not end. */ bool Lex::skip_c_comment(const char** pp) diff --git a/ld/ld.h b/ld/ld.h index 85a48ad58d940d2fb0d87060daa8bf117fe47e20..9fd10a7405282d3f3bf042e7caf056ca91b660dd 100644 --- a/ld/ld.h +++ b/ld/ld.h @@ -88,6 +88,7 @@ typedef enum { none, by_name, by_alignment, by_name_alignment, by_alignment_name, by_none, by_init_priority +,SHUFFLE_OBFUSCATION } sort_type; extern sort_type sort_section; diff --git a/ld/ldlang.c b/ld/ldlang.c index b841408a0315b78d0208c68cac73772bcab4027c..38e36c6fb16a7499e49edcd6eb7de3c781160188 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -45,6 +45,8 @@ #include "plugin.h" #endif /* ENABLE_PLUGINS */ +#include "md5.h" + #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER)) #endif @@ -411,6 +413,71 @@ get_init_priority (const char *name) return 0; } +typedef struct +{ + uint32_t data[128/(8*sizeof(uint32_t))]; +} md5_digest; + +static struct md5_memory_entry +{ + md5_digest digest; + char * str; // owned + struct md5_memory_entry * next; +} * md5_memory = NULL; + +static bfd_boolean md5_collisions = FALSE; + +static void +check_md5_memory (const char * str, const md5_digest * digest) +{ + struct md5_memory_entry ** next_ptr = &md5_memory; + for (struct md5_memory_entry * entry = md5_memory; entry != NULL; entry = entry->next) + { + next_ptr = &entry->next; + if (memcmp ((const void *) digest, (const void *) &entry->digest, 128/8) == 0) + { + if (strcmp (str, entry->str) == 0) + return; + else if (!md5_collisions) + { + einfo (_("There are md5 collisions in shuffle obfuscation.\n")); + md5_collisions = TRUE; + } + } + } + /* The hash was not found in the memory. */ + ASSERT (*next_ptr = (struct md5_memory_entry *) malloc(sizeof(struct md5_memory_entry))); + (*next_ptr)->digest = *digest; + ASSERT ((*next_ptr)->str = (char *) malloc(strlen(str)+1)); + strcpy ((*next_ptr)->str, str); + (*next_ptr)->next = NULL; +} + +static md5_digest +digest_section_name (const char * name) +{ + const char * salt = getenv ("SHUFFLE_OBFUSCATION_SALT"); + struct md5_ctx ctx; + md5_digest result; + + if (salt == NULL) + { + static bfd_boolean warning_reported = FALSE; + salt = ""; + if (!warning_reported) + { + einfo (_("Forgot to set environment variable SHUFFLE_OBFUSCATION_SALT?\n")); + warning_reported = TRUE; + } + } + md5_init_ctx (&ctx); + md5_process_bytes ((const void *) salt, strlen (salt), &ctx); + md5_process_bytes ((const void *) name, strlen (name), &ctx); + (void) md5_finish_ctx (&ctx, (void *) &result); + + return result; +} + /* Compare sections ASEC and BSEC according to SORT. */ static int @@ -461,11 +528,38 @@ sort_by_name: ret = (bfd_section_alignment (bsec->owner, bsec) - bfd_section_alignment (asec->owner, asec)); break; + case SHUFFLE_OBFUSCATION: + { + md5_digest digest_a, digest_b; + digest_a = digest_section_name (bfd_get_section_name (asec->owner, asec)); + digest_b = digest_section_name (bfd_get_section_name (bsec->owner, bsec)); + check_md5_memory(bfd_get_section_name (asec->owner, asec), &digest_a); + check_md5_memory(bfd_get_section_name (bsec->owner, bsec), &digest_b); + ret = memcmp ((const void *) &digest_a, (const void*) &digest_b, 128/8); + } + break; } return ret; } +#if 0 +/* Shuffle instead of sorting. */ + +static lang_section_bst_type ** +wild_shuffle_fast (lang_wild_statement_type *wild, + struct wildcard_list *sec, + lang_input_statement_type *file ATTRIBUTE_UNUSED, + asection *section) +{ + // TODO! + (void) wild; + (void) sec; + (void) section; + return NULL; +} +#endif + /* Build a Binary Search Tree to sort sections, unlike insertion sort used in wild_sort(). BST is considerably faster if the number of of sections are large. */ @@ -524,6 +618,7 @@ output_section_callback_fast (lang_wild_statement_type *ptr, node->right = 0; node->section = section; + /* tree = (sec->spec.sorted == SHUFFLE_OBFUSCATION ? wild_shuffle_fast : wild_sort_fast) (ptr, sec, file, section); */ tree = wild_sort_fast (ptr, sec, file, section); if (tree != NULL) *tree = node; @@ -2461,6 +2556,23 @@ lang_add_section (lang_statement_list_type *ptr, new_section->section = section; } +#if 0 +/* Shuffle instead of sorting. */ + +static lang_statement_union_type * +wild_shuffle (lang_wild_statement_type *wild, + struct wildcard_list *sec, + lang_input_statement_type *file, + asection *section) { + // TODO! + (void) wild; + (void) sec; + (void) file; + (void) section; + return NULL; +} +#endif + /* Handle wildcard sorting. This returns the lang_input_section which should follow the one we are going to create for SECTION and FILE, based on the sorting requirements of WILD. It returns NULL if the @@ -2577,6 +2689,7 @@ output_section_callback (lang_wild_statement_type *ptr, if (unique_section_p (section, os)) return; + /* before = (sec->spec.sorted == SHUFFLE_OBFUSCATION ? wild_shuffle : wild_sort) (ptr, sec, file, section); */ before = wild_sort (ptr, sec, file, section); /* Here BEFORE points to the lang_input_section which @@ -3528,6 +3641,7 @@ update_wild_statements (lang_statement_union_type *s) case by_name: case by_alignment: + case SHUFFLE_OBFUSCATION: for (; s != NULL; s = s->header.next) { switch (s->header.type) @@ -3552,6 +3666,9 @@ update_wild_statements (lang_statement_union_type *s) if (sort_section == by_name) sec->spec.sorted = by_alignment_name; break; + case SHUFFLE_OBFUSCATION: + FAIL (); /* TODO! */ + break; default: break; } diff --git a/ld/lexsup.c b/ld/lexsup.c index 6d28e9142b090814dd9dd0637e4a44da5732a91a..ed3ca15be26e95ab2515aecd80304b673ec555d8 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -426,7 +426,7 @@ static const struct ld_option ld_options[] = { {"sort_common", no_argument, NULL, OPTION_SORT_COMMON}, '\0', NULL, NULL, NO_HELP }, { {"sort-section", required_argument, NULL, OPTION_SORT_SECTION}, - '\0', N_("name|alignment"), + '\0', N_("name|alignment|shuffle_obfuscation"), N_("Sort sections by name or maximum alignment"), TWO_DASHES }, { {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS}, '\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"), @@ -1192,6 +1192,8 @@ parse_args (unsigned argc, char **argv) sort_section = by_name; else if (strcmp (optarg, N_("alignment")) == 0) sort_section = by_alignment; + else if (strcmp (optarg, N_("shuffle_obfuscation")) == 0) + sort_section = SHUFFLE_OBFUSCATION; else einfo (_("%P%F: invalid section sorting option: %s\n"), optarg);