[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