[aarch64] Add support for pointer authentication B key

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.

2018-12-05  Sam Tebbs  <sam.tebbs@arm.com>

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

gas/
	* dw2gencfi.c (struct cie_entry): Add tc_cie_entry_extras invocation.
	(alloc_fde_entry): Add tc_fde_entry_init_extra invocation.
	(output_cie): Add tc_output_cie_extra invocation.
	(select_cie_for_fde): Add tc_cie_fde_equivalent_extra and
	tc_cie_entry_init_extra invocation.
	(frch_cfi_data, cfa_save_data): Move to dwgencfi.h.
	* config/tc-aarch64.c (s_aarch64_cfi_b_key_frame): Declare.
	(md_pseudo_table): Add "cfi_b_key_frame".
	* config/tc-aarch64.h (tc_fde_entry_extras, tc_cie_entry_extras,
	tc_fde_entry_init_extra, tc_output_cie_extra,
	tc_cie_fde_equivalent_extra, tc_cie_entry_init_extra): Define.
	* dw2gencfi.h (struct fde_entry): Add tc_fde_entry_extras invocation.
	(pointer_auth_key): Define.
	(frch_cfi_data, cfa_save_data): Move from dwgencfi.c.
	* doc/c-aarch64.texi (.cfi_b_key_frame): Add documentation.
	* testsuite/gas/aarch64/(pac_ab_key.d, pac_ab_key.s): New file.
This commit is contained in:
Sam Tebbs 2018-12-05 18:27:23 +00:00 committed by Thomas Preud'homme
parent 90af06793e
commit 3a67e1a6b4
9 changed files with 156 additions and 16 deletions

View File

@ -1,3 +1,7 @@
2018-12-05 Sam Tebbs <sam.tebbs@arm.com>
* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Add check for 'B'.
2018-12-04 H.J. Lu <hongjiu.lu@intel.com>
PR ld/23372

View File

@ -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);

View File

@ -1,3 +1,22 @@
2018-12-05 Sam Tebbs <sam.tebbs@arm.com>
* dw2gencfi.c (struct cie_entry): Add tc_cie_entry_extras invocation.
(alloc_fde_entry): Add tc_fde_entry_init_extra invocation.
(output_cie): Add tc_output_cie_extra invocation.
(select_cie_for_fde): Add tc_cie_fde_equivalent_extra and
tc_cie_entry_init_extra invocation.
(frch_cfi_data, cfa_save_data): Move to dwgencfi.h.
* config/tc-aarch64.c (s_aarch64_cfi_b_key_frame): Declare.
(md_pseudo_table): Add "cfi_b_key_frame".
* config/tc-aarch64.h (tc_fde_entry_extras, tc_cie_entry_extras,
tc_fde_entry_init_extra, tc_output_cie_extra,
tc_cie_fde_equivalent_extra, tc_cie_entry_init_extra): Define.
* dw2gencfi.h (struct fde_entry): Add tc_fde_entry_extras invocation.
(pointer_auth_key): Define.
(frch_cfi_data, cfa_save_data): Move from dwgencfi.c.
* doc/c-aarch64.texi (.cfi_b_key_frame): Add documentation.
* testsuite/gas/aarch64/(pac_ab_key.d, pac_ab_key.s): New file.
2018-12-04 wu.heng <wu.heng@zte.com.cn>
PR 23939

View File

@ -1993,6 +1993,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. */
@ -2067,6 +2075,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},

View File

@ -435,6 +435,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

View File

@ -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;
}
@ -1872,6 +1858,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');
@ -2052,6 +2040,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)
@ -2158,6 +2147,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

View File

@ -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. */

View File

@ -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

View File

@ -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