From: Matthieu Longo Date: Mon, 28 Oct 2024 18:12:38 +0000 (+0000) Subject: aarch64: group software protection options under a same struct. X-Git-Tag: gdb-16-branchpoint~242 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=23189e9db77b280f88bb55ca8748e7edb72c61b1;p=thirdparty%2Fbinutils-gdb.git aarch64: group software protection options under a same struct. - declare a new struc aarch_protection_opts to store all the configuration options related to software protections (i.e. bti-plt, pac-plt, bti-report level). - add a new option "-z bti-report" to configure the log level of reported issues when BTI PLT is forced. - encapsulate the BTI report inside _bfd_aarch64_elf_check_bti_report. --- diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 7c4ef36c994..8500a50160f 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -2542,12 +2542,8 @@ struct elf_aarch64_obj_tdata /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */ uint32_t gnu_and_prop; - /* Zero to warn when linking objects with incompatible - GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */ - int no_bti_warn; - - /* PLT type based on security. */ - aarch64_plt_type plt_type; + /* Software protections options. */ + struct aarch64_protection_opts sw_protections; }; #define elf_aarch64_tdata(bfd) \ @@ -5024,7 +5020,7 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, int fix_erratum_835769, erratum_84319_opts fix_erratum_843419, int no_apply_dynamic_relocs, - aarch64_bti_pac_info bp_info) + const aarch64_protection_opts *sw_protections) { struct elf_aarch64_link_hash_table *globals; @@ -5041,19 +5037,15 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn; - switch (bp_info.bti_type) - { - case BTI_WARN: - elf_aarch64_tdata (output_bfd)->no_bti_warn = 0; - elf_aarch64_tdata (output_bfd)->gnu_and_prop - |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; - break; + /* Note: gnu_property_aarch64_feature_1_and was initialized to 0 by + bfd_zalloc(). */ + if (sw_protections->plt_type & PLT_BTI) + elf_aarch64_tdata (output_bfd)->gnu_and_prop + |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; - default: - break; - } - elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type; - setup_plt_values (link_info, bp_info.plt_type); + elf_aarch64_tdata (output_bfd)->sw_protections = *sw_protections; + + setup_plt_values (link_info, sw_protections->plt_type); } static bfd_vma @@ -9857,16 +9849,18 @@ elfNN_aarch64_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, && !add_dynamic_entry (DT_AARCH64_VARIANT_PCS, 0)) return false; - if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC) + aarch64_plt_type plt_type + = elf_aarch64_tdata (output_bfd)->sw_protections.plt_type; + if ((plt_type == PLT_BTI_PAC) && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0) || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))) return false; - else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI) + else if ((plt_type == PLT_BTI) && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)) return false; - else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC) + else if ((plt_type == PLT_PAC) && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)) return false; } @@ -9950,7 +9944,7 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h, /* First instruction in BTI enabled PLT stub is a BTI instruction so skip it. */ - if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI + if (elf_aarch64_tdata (output_bfd)->sw_protections.plt_type & PLT_BTI && elf_elfheader (output_bfd)->e_type == ET_EXEC) plt_entry = plt_entry + 4; @@ -10278,7 +10272,7 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED, /* First instruction in BTI enabled PLT stub is a BTI instruction so skip it. */ bfd_byte *plt0_entry = htab->root.splt->contents; - if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI) + if (elf_aarch64_tdata (output_bfd)->sw_protections.plt_type & PLT_BTI) plt0_entry = plt0_entry + 4; /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8. @@ -10377,7 +10371,8 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry; htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE; - aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type; + aarch64_plt_type type + = elf_aarch64_tdata (output_bfd)->sw_protections.plt_type; if (type == PLT_BTI || type == PLT_BTI_PAC) { entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry; @@ -10543,7 +10538,7 @@ elfNN_aarch64_get_synthetic_symtab (bfd *abfd, asymbol **dynsyms, asymbol **ret) { - elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd); + elf_aarch64_tdata (abfd)->sw_protections.plt_type = get_plt_type (abfd); return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, dynsymcount, dynsyms, ret); } @@ -10558,19 +10553,21 @@ elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt, size_t plt0_size = PLT_ENTRY_SIZE; size_t pltn_size = PLT_SMALL_ENTRY_SIZE; - if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC) + aarch64_plt_type plt_type + = elf_aarch64_tdata (plt->owner)->sw_protections.plt_type; + if (plt_type == PLT_BTI_PAC) { if (elf_elfheader (plt->owner)->e_type == ET_EXEC) pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE; else pltn_size = PLT_PAC_SMALL_ENTRY_SIZE; } - else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI) + else if (plt_type == PLT_BTI) { if (elf_elfheader (plt->owner)->e_type == ET_EXEC) pltn_size = PLT_BTI_SMALL_ENTRY_SIZE; } - else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC) + else if (plt_type == PLT_PAC) { pltn_size = PLT_PAC_SMALL_ENTRY_SIZE; } @@ -10618,12 +10615,13 @@ elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym) static bfd * elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info) { - uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop; + struct elf_aarch64_obj_tdata * tdata = elf_aarch64_tdata (info->output_bfd); + uint32_t prop = tdata->gnu_and_prop; bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop); - elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop; - elf_aarch64_tdata (info->output_bfd)->plt_type + tdata->gnu_and_prop = prop; + tdata->sw_protections.plt_type |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0; - setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type); + setup_plt_values (info, tdata->sw_protections.plt_type); return pbfd; } @@ -10639,28 +10637,26 @@ elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info, uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop; - /* If output has been marked with BTI using command line argument, give out - warning if necessary. */ /* Properties are merged per type, hence only check for warnings when merging GNU_PROPERTY_AARCH64_FEATURE_1_AND. */ - if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) - || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)) - && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) - && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn)) + if ((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) + || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)) { - if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) - || !aprop) - { - _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when " - "all inputs do not have BTI in NOTE section."), - abfd); - } - if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) - || !bprop) + const aarch64_protection_opts *sw_protections + = &elf_aarch64_tdata (info->output_bfd)->sw_protections; + aarch64_bti_report bti_report = sw_protections->bti_report; + + /* If output has been marked with BTI using command line argument, give + out warning if necessary. */ + if ((prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) + && (bti_report != BTI_NONE)) { - _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when " - "all inputs do not have BTI in NOTE section."), - bbfd); + if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) + || !aprop) + _bfd_aarch64_elf_check_bti_report (bti_report, abfd); + if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) + || !bprop) + _bfd_aarch64_elf_check_bti_report (bti_report, bbfd); } } diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c index d1279adc2e4..b4dd523203a 100644 --- a/bfd/elfxx-aarch64.c +++ b/bfd/elfxx-aarch64.c @@ -814,7 +814,8 @@ _bfd_aarch64_elf_parse_gnu_properties (bfd *abfd, unsigned int type, return property_corrupt; } prop = _bfd_elf_get_property (abfd, type, datasz); - /* Combine properties of the same type. */ + /* Merge AArch64 feature properties together if they are declared in + different AARCH64_FEATURE_1_AND properties. */ prop->u.number |= bfd_h_get_32 (abfd, ptr); prop->pr_kind = property_number; break; @@ -922,3 +923,18 @@ _bfd_aarch64_elf_link_fixup_gnu_properties } } } + +/* Check AArch64 BTI report. */ +void +_bfd_aarch64_elf_check_bti_report (aarch64_bti_report bti_report, bfd *ebfd) +{ + if (bti_report == BTI_NONE) + return; + + const char *log_level = (bti_report == BTI_WARN ? "warning" : "error"); + + const char *msg = _("%pB: %s: BTI turned on by -z force-bti on the output " + "when all inputs do not have BTI in NOTE section."); + + _bfd_error_handler (msg, ebfd, log_level); +} \ No newline at end of file diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h index f21e5ee5efc..298edd4e6ed 100644 --- a/bfd/elfxx-aarch64.h +++ b/bfd/elfxx-aarch64.h @@ -34,27 +34,33 @@ extern void bfd_elf32_aarch64_init_maps typedef enum { PLT_NORMAL = 0x0, /* Normal plts. */ - PLT_BTI = 0x1, /* plts with bti. */ + PLT_BTI = 0x1, /* plts with BTI. */ PLT_PAC = 0x2, /* plts with pointer authentication. */ PLT_BTI_PAC = PLT_BTI | PLT_PAC } aarch64_plt_type; -/* To indicate if BTI is enabled with/without warning. */ +/* Indicates whether the linker should generate warnings/errors when input + objects are missing BTI markings and the output has BTI markings. */ typedef enum { - BTI_NONE = 0, /* BTI is not enabled. */ - BTI_WARN = 1, /* BTI is enabled with -z force-bti. */ -} aarch64_enable_bti_type; - -/* A structure to encompass all information coming from BTI or PAC - related command line options. This involves the "PLT_TYPE" to determine - which version of PLTs to pick and "BTI_TYPE" to determine if - BTI should be turned on with any warnings. */ -typedef struct + BTI_NONE = 0, /* Does not emit any warning/error messages. */ + BTI_WARN = 1, /* Emit warning when the input objects are missing BTI + markings and output have BTI marking. */ + BTI_ERROR = 2, /* Emit error when the input objects are missing BTI + markings and output have BTI marking. */ +} aarch64_bti_report; + +/* A structure to encompass all information about software protections coming + from BTI or PAC related command line options. */ +struct aarch64_protection_opts { + /* PLT type to use depending on the selected software proctections. */ aarch64_plt_type plt_type; - aarch64_enable_bti_type bti_type; -} aarch64_bti_pac_info; + + /* Report level for BTI issues. */ + aarch64_bti_report bti_report; +}; +typedef struct aarch64_protection_opts aarch64_protection_opts; /* An enum to define what kind of erratum fixes we should apply. This gives the user a bit more control over the sequences we generate. */ @@ -67,11 +73,11 @@ typedef enum extern void bfd_elf64_aarch64_set_options (bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int, - aarch64_bti_pac_info); + const aarch64_protection_opts *); extern void bfd_elf32_aarch64_set_options (bfd *, struct bfd_link_info *, int, int, int, int, erratum_84319_opts, int, - aarch64_bti_pac_info); + const aarch64_protection_opts *); /* AArch64 stub generation support for ELF64. Called from the linker. */ extern int elf64_aarch64_setup_section_lists @@ -158,6 +164,9 @@ _bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *, bfd *, elf_property *, elf_property *, uint32_t); +extern void +_bfd_aarch64_elf_check_bti_report (aarch64_bti_report, bfd *); + extern void _bfd_aarch64_elf_link_fixup_gnu_properties (struct bfd_link_info *, elf_property_list **); diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index c5edf26366d..33b239b957a 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -34,8 +34,13 @@ static int pic_veneer = 0; static int fix_erratum_835769 = 0; static erratum_84319_opts fix_erratum_843419 = ERRAT_NONE; static int no_apply_dynamic_relocs = 0; -static aarch64_plt_type plt_type = PLT_NORMAL; -static aarch64_enable_bti_type bti_type = BTI_NONE; +static aarch64_protection_opts sw_protections = { + .plt_type = PLT_NORMAL, + .bti_report = BTI_WARN, +}; + +#define COMPILE_TIME_STRLEN(s) \ + (sizeof(s) - 1) static void gld${EMULATION_NAME}_before_parse (void) @@ -321,17 +326,13 @@ aarch64_elf_create_output_section_statements (void) return; } - aarch64_bti_pac_info bp_info; - bp_info.plt_type = plt_type; - bp_info.bti_type = bti_type; - bfd_elf${ELFSIZE}_aarch64_set_options (link_info.output_bfd, &link_info, no_enum_size_warning, no_wchar_size_warning, pic_veneer, fix_erratum_835769, fix_erratum_843419, no_apply_dynamic_relocs, - bp_info); + &sw_protections); stub_file = lang_add_input_file ("linker stubs", lang_input_file_is_fake_enum, @@ -350,6 +351,30 @@ aarch64_elf_create_output_section_statements (void) ldlang_add_file (stub_file); } +static bool +aarch64_parse_bti_report_option (const char *optarg) +{ + #define BTI_REPORT "bti-report" + #define BTI_REPORT_LEN COMPILE_TIME_STRLEN (BTI_REPORT) + + if (strncmp (optarg, BTI_REPORT, BTI_REPORT_LEN) != 0) + return false; + + if (strlen (optarg) == BTI_REPORT_LEN + || strcmp (optarg + BTI_REPORT_LEN, "=warning") == 0) + sw_protections.bti_report = BTI_WARN; + else if (strcmp (optarg + BTI_REPORT_LEN, "=none") == 0) + sw_protections.bti_report = BTI_NONE; + else if (strcmp (optarg + BTI_REPORT_LEN, "=error") == 0) + sw_protections.bti_report = BTI_ERROR; + else + einfo (_("%X%P: error: unrecognized value '-z %s'\n"), optarg); + + return true; + + #undef BTI_REPORT + #undef BTI_REPORT_LEN +} EOF # Define some shell vars to insert bits of code into the standard elf @@ -396,18 +421,27 @@ PARSE_AND_LIST_OPTIONS=' instruction into an ADR. As such the workaround will always use a\n\ veneer and this will give you both a performance and size overhead.\n")); fprintf (file, _(" --no-apply-dynamic-relocs Do not apply link-time values for dynamic relocations\n")); - fprintf (file, _(" -z force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n")); - fprintf (file, _(" -z pac-plt Protect PLTs with Pointer Authentication.\n")); + fprintf (file, _("\ + -z force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI.\n\ + Generate warnings for missing BTI markings on inputs\n")); + fprintf (file, _("\ + -z bti-report[=none|warning|error] Emit warning/error on mismatch of BTI marking between input objects and ouput.\n\ + none: Does not emit any warning/error messages.\n\ + warning (default): Emit warning when the input objects are missing BTI markings\n\ + and output has BTI marking.\n\ + error: Emit error when the input objects are missing BTI markings\n\ + and output has BTI marking.\n")); + fprintf (file, _("\ + -z pac-plt Protect PLTs with Pointer Authentication.\n")); ' PARSE_AND_LIST_ARGS_CASE_Z_AARCH64=' - else if (strcmp (optarg, "force-bti") == 0) - { - plt_type |= PLT_BTI; - bti_type = BTI_WARN; - } - else if (strcmp (optarg, "pac-plt") == 0) - plt_type |= PLT_PAC; + else if (strcmp (optarg, "force-bti") == 0) + sw_protections.plt_type |= PLT_BTI; + else if (aarch64_parse_bti_report_option (optarg)) + {} + else if (strcmp (optarg, "pac-plt") == 0) + sw_protections.plt_type |= PLT_PAC; ' PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_AARCH64"