This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][BINUTILS][AARCH64] Add support for pointer authentication B key


Hi all,

Armv8.3-A has another key used in pointer authentication called the B-key (other
than the A-key that is already supported). In order for stack unwinders to work
it is necessary to be able to identify frames that have been signed with the
B-key rather than the A-key and it was felt that keeping this as an augmentation
character in the CIE was the best bet. The DWARF extensions for ARM therefore
propose to add a new augmentation character 'B' to the CIE augmentation string
and the corresponding cfi directive ".cfi_b_key_frame". I've made the relevant
changes to GAS and LD to add support for B-key unwinding, which required
modifying LD to check for 'B' in the augmentation string, adding the
".cfi_b_key_frame" directive to GAS and adding a "pauth_key" field to GAS's
fde_entry and cie_entry structs.

The pointer authentication instructions will behave as NOPs on architectures
that don't support them, and so a check for the architecture being assembled
for is not necessary since there will be no behavioural difference between
augmentation strings with and without the 'B' character on such architectures.

Built on aarch64-linux-gnu and aarch64-none-elf, and tested on aarch64-none-elf
with no regressions. This patch has been tested with the corresponding patch
that enables B-key support in GCC.

OK for trunk? I don't have write access so I'd appreciate someone committing
after approval.

bfd/
2018-11-01  Sam Tebbs<sam.tebbs@arm.com>

	* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Add check for 'B'.

gas/
2018-11-01  Sam Tebbs<sam.tebbs@arm.com>

	* dw2gencfi.c (struct cie_entry): Add pauth_key field.
	(alloc_fde_entry): Set pauth_key to AARCH64_PAUTH_KEY_A by default.
	(output_cie): Output 'B' if pauth_key == AARCH64_PAUTH_KEY_B.
	(select_cie_for_fde): Add check for pauth_key. Set cie's pauth_key to
	fde's pauth_key.
	(frch_cfi_data, cfa_save_data): Move to dwgencfi.h.
	* config/tc-aarch64.c (dot_cfi_b_key_frame): Declare.
	(md_pseudo_table): Add "cfi_b_key_frame".
	* dw2gencfi.h (pointer_auth_key): Define.
	(struct fde_entry): Add pauth_key field.
	(frch_cfi_data, cfa_save_data): Move from dwgencfi.c.

gas/doc/
2018-11-01  Sam Tebbs<sam.tebbs@arm.com>

	* c-aarch64.texi (.cfi_b_key_frame): Add documentation.

gas/testsuite
2018-11-01  Sam Tebbs<sam.tebbs@arm.com>

	* gas/aarch64/(pac_ab_key.d, pac_ab_key.s): New file.

diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index 12f06ef9baa150cf460b451dad9cacd37116b19c..b76a657709f94b64a21bd458aed7f83304bca0dd 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -797,6 +797,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
 	      while (*aug != '\0')
 		switch (*aug++)
 		  {
+		  case 'B':
+		    break;
 		  case 'L':
 		    REQUIRE (read_byte (&buf, end, &cie->lsda_encoding));
 		    ENSURE_NO_RELOCS (buf);
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 085ffa26f0e4594fe97b50d19d79e27f742f34e6..e0861512fe5204f1cefcd1e7583f3c55c1be4b10 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -1992,6 +1992,14 @@ s_aarch64_inst (int ignored ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+static void
+s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+  struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data;
+  fde->pauth_key = AARCH64_PAUTH_KEY_B;
+}
+
 #ifdef OBJ_ELF
 /* Emit BFD_RELOC_AARCH64_TLSDESC_ADD on the next ADD instruction.  */
 
@@ -2066,6 +2074,7 @@ const pseudo_typeS md_pseudo_table[] = {
   {"arch", s_aarch64_arch, 0},
   {"arch_extension", s_aarch64_arch_extension, 0},
   {"inst", s_aarch64_inst, 0},
+  {"cfi_b_key_frame", s_aarch64_cfi_b_key_frame, 0},
 #ifdef OBJ_ELF
   {"tlsdescadd", s_tlsdescadd, 0},
   {"tlsdesccall", s_tlsdesccall, 0},
diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
index b659b8ba5971b964fbdf3357c97093471227db67..26c68efc8f522d9d4379a0ab61073d6839bc9b28 100644
--- a/gas/doc/c-aarch64.texi
+++ b/gas/doc/c-aarch64.texi
@@ -424,6 +424,14 @@ as the @code{.dword} directive.
 @c YYYYYYYYYYYYYYYYYYYYYYYYYY
 @c ZZZZZZZZZZZZZZZZZZZZZZZZZZ
 
+@cindex @code{.cfi_b_key_frame} directive, AArch64
+@item	@code{.cfi_b_key_frame}
+The @code{.cfi_b_key_frame} directive inserts a 'B' character into the CIE
+corresponding to the current frame's FDE, meaning that its return address has
+been signed with the B-key.  If two frames are signed with differing keys then
+they will not share the same CIE.  This information is intended to be used by
+the stack unwinder in order to properly authenticate return addresses.
+
 @end table
 
 @node AArch64 Opcodes
diff --git a/gas/dw2gencfi.h b/gas/dw2gencfi.h
index cf534b477696eb5f718b47fdf2bb55d89beafec2..2b1362a2bb02161e8b9e6c8b781e38f39fd319d8 100644
--- a/gas/dw2gencfi.h
+++ b/gas/dw2gencfi.h
@@ -135,6 +135,27 @@ enum {
   EH_COMPACT_HAS_LSDA
 };
 
+enum pointer_auth_key {
+  AARCH64_PAUTH_KEY_A,
+  AARCH64_PAUTH_KEY_B
+};
+
+/* Stack of old CFI data, for save/restore.  */
+struct cfa_save_data
+{
+  struct cfa_save_data *next;
+  offsetT cfa_offset;
+};
+
+/* Current open FDE entry.  */
+struct frch_cfi_data
+{
+  struct fde_entry *cur_fde_data;
+  symbolS *last_address;
+  offsetT cur_cfa_offset;
+  struct cfa_save_data *cfa_save_stack;
+};
+
 struct fde_entry
 {
   struct fde_entry *next;
@@ -162,6 +183,8 @@ struct fde_entry
   /* For out of line tables and FDEs.  */
   symbolS *eh_loc;
   int sections;
+  /* The pointer authentication key used.  Only used for AArch64.  */
+  enum pointer_auth_key pauth_key;
 };
 
 /* The list of all FDEs that have been collected.  */
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 3b610708022645d2544175cf53d19f4ced4fa8df..389d7e766a9bbf87c87876c0331cea462def3633 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -403,6 +403,7 @@ struct cie_entry
   unsigned char per_encoding;
   unsigned char lsda_encoding;
   expressionS personality;
+  enum pointer_auth_key pauth_key;
   struct cfi_insn_data *first, *last;
 };
 
@@ -414,22 +415,6 @@ static struct fde_entry **last_fde_data = &all_fde_data;
 /* List of CIEs so that they could be reused.  */
 static struct cie_entry *cie_root;
 
-/* Stack of old CFI data, for save/restore.  */
-struct cfa_save_data
-{
-  struct cfa_save_data *next;
-  offsetT cfa_offset;
-};
-
-/* Current open FDE entry.  */
-struct frch_cfi_data
-{
-  struct fde_entry *cur_fde_data;
-  symbolS *last_address;
-  offsetT cur_cfa_offset;
-  struct cfa_save_data *cfa_save_stack;
-};
-
 /* Construct a new FDE structure and add it to the end of the fde list.  */
 
 static struct fde_entry *
@@ -448,6 +433,7 @@ alloc_fde_entry (void)
   fde->per_encoding = DW_EH_PE_omit;
   fde->lsda_encoding = DW_EH_PE_omit;
   fde->eh_header_type = EH_COMPACT_UNKNOWN;
+  fde->pauth_key = AARCH64_PAUTH_KEY_A;
 
   return fde;
 }
@@ -1581,7 +1567,7 @@ dot_cfi_personality_id (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 #endif
-
+
 static void
 output_cfi_insn (struct cfi_insn_data *insn)
 {
@@ -1864,6 +1850,8 @@ output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align)
       if (cie->lsda_encoding != DW_EH_PE_omit)
 	out_one ('L');
       out_one ('R');
+      if (cie->pauth_key == AARCH64_PAUTH_KEY_B)
+	out_one ('B');
     }
   if (cie->signal_frame)
     out_one ('S');
@@ -2044,6 +2032,7 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
       if (CUR_SEG (cie) != CUR_SEG (fde))
 	continue;
       if (cie->return_column != fde->return_column
+	  || cie->pauth_key != fde->pauth_key
 	  || cie->signal_frame != fde->signal_frame
 	  || cie->per_encoding != fde->per_encoding
 	  || cie->lsda_encoding != fde->lsda_encoding)
@@ -2150,6 +2139,7 @@ select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
   cie->lsda_encoding = fde->lsda_encoding;
   cie->personality = fde->personality;
   cie->first = fde->data;
+  cie->pauth_key = fde->pauth_key;
 
   for (i = cie->first; i ; i = i->next)
     if (i->insn == DW_CFA_advance_loc
diff --git a/gas/testsuite/gas/aarch64/pac_ab_key.d b/gas/testsuite/gas/aarch64/pac_ab_key.d
new file mode 100644
index 0000000000000000000000000000000000000000..a428633448900123d76edff641f03234a418f348
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/pac_ab_key.d
@@ -0,0 +1,54 @@
+#objdump: --dwarf=frames
+# Test assembling a file with functions signed by two different pointer
+# authentication keys. It must interpret .cfi_b_key_frame properly and emit a
+# 'B' character into the correct CIE's augmentation string.
+
+.+:     file .+
+
+Contents of the .eh_frame section:
+
+00000000 0000000000000010 00000000 CIE
+  Version:               1
+  Augmentation:          "zR"
+  Code alignment factor: 4
+  Data alignment factor: -8
+  Return address column: 30
+  Augmentation data:     1b
+  DW_CFA_def_cfa: r31 \(sp\) ofs 0
+
+00000014 0000000000000018 00000018 FDE cie=00000000 pc=0000000000000000..0000000000000008
+  DW_CFA_advance_loc: 4 to 0000000000000004
+  DW_CFA_GNU_window_save
+  DW_CFA_advance_loc: 4 to 0000000000000008
+  DW_CFA_def_cfa_offset: 16
+  DW_CFA_offset: r29 \(x29\) at cfa-16
+  DW_CFA_offset: r30 \(x30\) at cfa-8
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000030 0000000000000014 00000000 CIE
+  Version:               1
+  Augmentation:          "zRB"
+  Code alignment factor: 4
+  Data alignment factor: -8
+  Return address column: 30
+  Augmentation data:     1b
+  DW_CFA_def_cfa: r31 \(sp\) ofs 0
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000048 000000000000001c 0000001c FDE cie=00000030 pc=0000000000000008..0000000000000010
+  DW_CFA_advance_loc: 4 to 000000000000000c
+  DW_CFA_GNU_window_save
+  DW_CFA_advance_loc: 4 to 0000000000000010
+  DW_CFA_def_cfa_offset: 16
+  DW_CFA_offset: r29 \(x29\) at cfa-16
+  DW_CFA_offset: r30 \(x30\) at cfa-8
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
diff --git a/gas/testsuite/gas/aarch64/pac_ab_key.s b/gas/testsuite/gas/aarch64/pac_ab_key.s
new file mode 100644
index 0000000000000000000000000000000000000000..4b328e72ae456ca139b16de4e38528cde9ccca27
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/pac_ab_key.s
@@ -0,0 +1,31 @@
+	.arch armv8-a
+	.text
+	.align	2
+	.global	_Z5foo_av
+	.type	_Z5foo_av, %function
+_Z5foo_av:
+.LFB0:
+	.cfi_startproc
+	hint	25 // paciasp
+	.cfi_window_save
+	stp	x29, x30, [sp, -16]!
+	.cfi_def_cfa_offset 16
+	.cfi_offset 29, -16
+	.cfi_offset 30, -8
+	.cfi_endproc
+.LFE0:
+	.size	_Z5foo_av, .-_Z5foo_av
+	.align	2
+	.global	_Z5foo_bv
+	.type	_Z5foo_bv, %function
+_Z5foo_bv:
+.LFB1:
+	.cfi_startproc
+	.cfi_b_key_frame
+	hint	27 // pacibsp
+	.cfi_window_save
+	stp	x29, x30, [sp, -16]!
+	.cfi_def_cfa_offset 16
+	.cfi_offset 29, -16
+	.cfi_offset 30, -8
+	.cfi_endproc

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]