[PATCH v1 10/27] aarch64: group software protection options under a same struct.

Matthieu Longo matthieu.longo@arm.com
Mon Dec 2 14:22:02 GMT 2024


- 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.
---
 bfd/elfnn-aarch64.c        | 98 ++++++++++++++++++--------------------
 bfd/elfxx-aarch64.c        | 18 ++++++-
 bfd/elfxx-aarch64.h        | 39 +++++++++------
 ld/emultempl/aarch64elf.em | 66 ++++++++++++++++++-------
 4 files changed, 138 insertions(+), 83 deletions(-)

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"
 
-- 
2.47.0



More information about the Binutils mailing list