This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH][BINUTILS][AARCH64] Add support for pointer authentication B key
On 11/9/18 4:31 PM, Nick Clifton wrote:
> Hi Sam,
>
>>>> The DWARF extensions for ARM therefore
>>> Are these extensions documented somewhere ?
>> There is no public documentation for this approach as it was agreed upon
>> internally with those implementing support in LLVM. I have documented
>> this in gas/doc/c-aarch64.texi, would you like me to refer to that
>> section from the relevant source code?
> No. I was just hoping that there would be a pdf accessible on the web
> somewhere that contained a description of the exntensions to the CFI
> encoding used by AArch64. In the past ARM have been very good about
> creating such documents... :-)
>
> [Ah - just read Ramana's email, so it looks like this point is now covered.
> Please could the Dwarf supplement be referenced in a comment in the revised
> patch set ?]
>
I will have to follow up with the revision once it is published which
there is no concrete ETA for yet.
>>> Did you also test on an non AArch64 configuration, just to be sure, eg x86_64-pc-linux-gnu ?
>> I haven't actually, but will do so and report back. Would just this
>> other configuration suffice?
> Yes. I am not actually expecting any problems. But testing the
> most popular non-ARM target configuration would be a good idea.
I have now successfully tested and built the patch on
x86_64-pc-linux-gnu with no problems.
>> Adding a definition of the encoding character to a header could perhaps
>> coincide with your suggestions below, in that I could add a macro called
>> "tc_is_valid_aug_char" which the target defines. That would mean we
>> could avoid having such an encoding definition in a target-agnostic
>> file. Let me know what you think.
> The tc_xxx terminology is only used inside gas, whereas we want these characters
> to be processed in lots of different places, (gas, libbfd, readelf, etc). So I
> think that you might need to put the encoding characters into a more generic
> header file like include/elf/common.h or maybe include/elf/cfi.h.
>
As you suggested in an earlier email, I think I will follow up with a
change to this in a later patch rather than include it in this one.
Attached is a revised patch with the target hooks implemented and
target-specific definitions (pointer_auth_key etc.).
bfd/
2018-11-20 Sam Tebbs <sam.tebbs@arm.com>
* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Add check for 'B'.
binutils/
2018-11-20 Sam Tebbs <sam.tebbs@arm.com>
* dwarf.c (read_cie): Add check for 'B'.
gas/
2018-11-20 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.
gas/doc/
2018-11-20 Sam Tebbs <sam.tebbs@arm.com>
* c-aarch64.texi (.cfi_b_key_frame): Add documentation.
gas/testsuite
2018-11-20 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