Add support for pointer authentication
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Tue, 19 Feb 2019 11:53:51 +0000 (11:53 +0000)
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Wed, 27 Feb 2019 11:58:09 +0000 (11:58 +0000)
The previous commit added the infrastructure to load and save
ARMv8.3-PAuth registers during Non-secure <-> Secure world switches, but
didn't actually enable pointer authentication in the firmware.

This patch adds the functionality needed for platforms to provide
authentication keys for the firmware, and a new option (ENABLE_PAUTH) to
enable pointer authentication in the firmware itself. This option is
disabled by default, and it requires CTX_INCLUDE_PAUTH_REGS to be
enabled.

Change-Id: I35127ec271e1198d43209044de39fa712ef202a5
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
13 files changed:
Makefile
bl31/aarch64/ea_delegate.S
bl31/aarch64/runtime_exceptions.S
common/bl_common.c
docs/firmware-design.rst
docs/porting-guide.rst
docs/user-guide.rst
include/arch/aarch64/arch_features.h
include/arch/aarch64/arch_helpers.h
include/common/bl_common.h
include/plat/common/platform.h
lib/el3_runtime/aarch64/context.S
make_helpers/defaults.mk

index ebc885091c9daf292f52a11d92cb5753041a5ecf..7b0ef5b42a697c594aa345117c21e5421836e32e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -184,6 +184,14 @@ TF_CFLAGS_aarch64  +=      -mgeneral-regs-only -mstrict-align
 ASFLAGS_aarch32                =       $(march32-directive)
 ASFLAGS_aarch64                =       -march=armv8-a
 
+# Set the compiler to ARMv8.3 mode so that it uses all the ARMv8.3-PAuth
+# instructions. Keeping it in 8.0 would make the compiler emit
+# backwards-compatible hint instructions, which needs more space.
+ifeq (${ENABLE_PAUTH},1)
+TF_CFLAGS_aarch64      +=      -march=armv8.3-a
+ASFLAGS_aarch64                +=      -march=armv8.3-a
+endif
+
 WARNING1 := -Wextra
 WARNING1 += -Wunused -Wno-unused-parameter
 WARNING1 += -Wmissing-declarations
@@ -459,6 +467,15 @@ ifeq ($(DYN_DISABLE_AUTH), 1)
     endif
 endif
 
+# If pointer authentication is used in the firmware, make sure that all the
+# registers associated to it are also saved and restored. Not doing it would
+# leak the value of the key used by EL3 to EL1 and S-EL1.
+ifeq ($(ENABLE_PAUTH),1)
+    ifeq ($(CTX_INCLUDE_PAUTH_REGS),0)
+        $(error ENABLE_PAUTH=1 requires CTX_INCLUDE_PAUTH_REGS=1)
+    endif
+endif
+
 ################################################################################
 # Process platform overrideable behaviour
 ################################################################################
@@ -587,6 +604,7 @@ $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
 $(eval $(call assert_boolean,ENABLE_AMU))
 $(eval $(call assert_boolean,ENABLE_ASSERTIONS))
 $(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
+$(eval $(call assert_boolean,ENABLE_PAUTH))
 $(eval $(call assert_boolean,ENABLE_PIE))
 $(eval $(call assert_boolean,ENABLE_PMF))
 $(eval $(call assert_boolean,ENABLE_PSCI_STAT))
@@ -639,6 +657,7 @@ $(eval $(call add_define,EL3_EXCEPTION_HANDLING))
 $(eval $(call add_define,ENABLE_AMU))
 $(eval $(call add_define,ENABLE_ASSERTIONS))
 $(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS))
+$(eval $(call add_define,ENABLE_PAUTH))
 $(eval $(call add_define,ENABLE_PIE))
 $(eval $(call add_define,ENABLE_PMF))
 $(eval $(call add_define,ENABLE_PSCI_STAT))
index d5ecfc50eedd6468bf45b9adc96c10aaa100e536..40c3191ac5f719a3caf8aec1273ce1bd45f321e2 100644 (file)
@@ -68,9 +68,13 @@ func enter_lower_el_sync_ea
        /* Save GP registers */
        bl      save_gp_registers
 
+       /* Save ARMv8.3-PAuth registers and load firmware key */
 #if CTX_INCLUDE_PAUTH_REGS
        bl      pauth_context_save
 #endif
+#if ENABLE_PAUTH
+       bl      pauth_load_bl_apiakey
+#endif
 
        /* Setup exception class and syndrome arguments for platform handler */
        mov     x0, #ERROR_EA_SYNC
@@ -102,9 +106,13 @@ func enter_lower_el_async_ea
        /* Save GP registers */
        bl      save_gp_registers
 
+       /* Save ARMv8.3-PAuth registers and load firmware key */
 #if CTX_INCLUDE_PAUTH_REGS
        bl      pauth_context_save
 #endif
+#if ENABLE_PAUTH
+       bl      pauth_load_bl_apiakey
+#endif
 
        /* Setup exception class and syndrome arguments for platform handler */
        mov     x0, #ERROR_EA_ASYNC
index cea7a8a1e88144166458ab4f7593c7130231d064..aa9d0079bea99bd589ecc0f9198cef1604847de1 100644 (file)
 
        bl      save_gp_registers
 
+       /* Save ARMv8.3-PAuth registers and load firmware key */
 #if CTX_INCLUDE_PAUTH_REGS
        bl      pauth_context_save
 #endif
+#if ENABLE_PAUTH
+       bl      pauth_load_bl_apiakey
+#endif
 
        /* Save the EL3 system registers needed to return from this exception */
        mrs     x0, spsr_el3
@@ -331,9 +335,13 @@ smc_handler64:
        /* Save general purpose registers */
        bl      save_gp_registers
 
+       /* Save ARMv8.3-PAuth registers and load firmware key */
 #if CTX_INCLUDE_PAUTH_REGS
        bl      pauth_context_save
 #endif
+#if ENABLE_PAUTH
+       bl      pauth_load_bl_apiakey
+#endif
 
        /*
         * Populate the parameters for the SMC handler.
index 84ff99c8e653bea6478e1f0be091f726f22b7c0c..4e76dd3e6d1af1f32a6b4217814d9e6102ab20ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <string.h>
 
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
@@ -243,3 +244,53 @@ void print_entry_point_info(const entry_point_info_t *ep_info)
 #endif
 #undef PRINT_IMAGE_ARG
 }
+
+#ifdef AARCH64
+/*******************************************************************************
+ * Handle all possible cases regarding ARMv8.3-PAuth.
+ ******************************************************************************/
+void bl_handle_pauth(void)
+{
+#if ENABLE_PAUTH
+       /*
+        * ENABLE_PAUTH = 1 && CTX_INCLUDE_PAUTH_REGS = 1
+        *
+        * Check that the system supports address authentication to avoid
+        * getting an access fault when accessing the registers. This is all
+        * that is needed to check. If any of the authentication mechanisms is
+        * supported, the system knows about ARMv8.3-PAuth, so all the registers
+        * are available and accessing them won't generate a fault.
+        *
+        * Obtain 128-bit instruction key A from the platform and save it to the
+        * system registers. Pointer authentication can't be enabled here or the
+        * authentication will fail when returning from this function.
+        */
+       assert(is_armv8_3_pauth_api_present());
+
+       uint64_t *apiakey = plat_init_apiakey();
+
+       write_apiakeylo_el1(apiakey[0]);
+       write_apiakeyhi_el1(apiakey[1]);
+#else /* if !ENABLE_PAUTH */
+
+# if CTX_INCLUDE_PAUTH_REGS
+       /*
+        * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 1
+        *
+        * Assert that the ARMv8.3-PAuth registers are present or an access
+        * fault will be triggered when they are being saved or restored.
+        */
+       assert(is_armv8_3_pauth_present());
+# else
+       /*
+        * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 0
+        *
+        * Pointer authentication is allowed in the Non-secure world, but
+        * prohibited in the Secure world. The Trusted Firmware doesn't save the
+        * registers during a world switch. No check needed.
+        */
+# endif /* CTX_INCLUDE_PAUTH_REGS */
+
+#endif /* ENABLE_PAUTH */
+}
+#endif /* AARCH64 */
index 808afeedb9e015245b9f55b1f673e255c888cdbf..ead7297d9d06d66931a17f70d0238a368e5fadd7 100644 (file)
@@ -2566,6 +2566,11 @@ Armv8.3-A
    must be set to 1. This will add all pointer authentication system registers
    to the context that is saved when doing a world switch.
 
+   The Trusted Firmware itself has support for pointer authentication at runtime
+   that can be enabled by setting both options ``ENABLE_PAUTH`` and
+   ``CTX_INCLUDE_PAUTH_REGS`` to 1. This enables pointer authentication in BL1,
+   BL2, BL31, and the TSP if it is used.
+
 Armv7-A
 ~~~~~~~
 
index 7a3963bda88c24b896d42cb91ac73d13cc7b5fc5..c3df389f81684c94c24bf1f42ac5d200ff913cf7 100644 (file)
@@ -1792,6 +1792,22 @@ defined by the translation library, and can be found in the file
 On DynamIQ systems, this function must not use stack while enabling MMU, which
 is how the function in xlat table library version 2 is implemented.
 
+Function : plat_init_apiakey [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint64_t *
+
+This function populates the ``plat_apiakey`` array that contains the values used
+to set the ``APIAKey{Hi,Lo}_EL1`` registers. It returns a pointer to this array.
+
+The value should be obtained from a reliable source of randomness.
+
+This function is only needed if ARMv8.3 pointer authentication is used in the
+Trusted Firmware by building with ``ENABLE_PAUTH=1``.
+
 Function : plat_get_syscnt_freq2() [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index 70c1d5a91cc221ef1f18d46a5367af6a8b0e8a23..b4201275770087f7227f5ed332f53265952e1c5e 100644 (file)
@@ -362,7 +362,7 @@ Common build options
    the ARMv8.3-PAuth registers to be included when saving and restoring the CPU
    context. Note that if the hardware supports this extension and this option is
    set to 0 the value of the registers will be leaked between Secure and
-   Non-secure worlds. The default is 0.
+   Non-secure worlds if PAuth is used on both sides. The default is 0.
 
 -  ``DEBUG``: Chooses between a debug and release build. It can take either 0
    (release) or 1 (debug) as values. 0 is the default.
@@ -411,6 +411,13 @@ Common build options
    partitioning in EL3, however. Platform initialisation code should configure
    and use partitions in EL3 as required. This option defaults to ``0``.
 
+-  ``ENABLE_PAUTH``: Boolean option to enable ARMv8.3 Pointer Authentication
+   (``ARMv8.3-PAuth``) support in the Trusted Firmware itself. Note that this
+   option doesn't affect the saving of the registers introduced with this
+   extension, they are always saved if they are detected regardless of the value
+   of this option. If enabled, it is needed to use a compiler that supports the
+   option ``-msign-return-address``. It defaults to 0.
+
 -  ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE)
    support within generic code in TF-A. This option is currently only supported
    in BL31. Default is 0.
index da8b6e4f1cf4554c6f7f4f9558204bd1ac583e2c..495ecb3a2f0a426102a052abfa7276ddc7f4f46f 100644 (file)
@@ -23,6 +23,23 @@ static inline bool is_armv8_2_ttcnp_present(void)
                ID_AA64MMFR2_EL1_CNP_MASK) != 0U;
 }
 
+static inline bool is_armv8_3_pauth_present(void)
+{
+       uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
+                       (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) |
+                       (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
+                       (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+
+       /* If any of the fields is not zero, PAuth is present */
+       return (read_id_aa64isar1_el1() & mask) != 0U;
+}
+
+static inline bool is_armv8_3_pauth_api_present(void)
+{
+       return ((read_id_aa64isar1_el1() >> ID_AA64ISAR1_API_SHIFT) &
+               ID_AA64ISAR1_API_MASK) != 0U;
+}
+
 static inline bool is_armv8_4_ttst_present(void)
 {
        return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) &
index 4e459bbb9adbd19d2fd67056b1cf25e93dfda0ec..e07db300b56c6c3651742da21111a9298ded3ad7 100644 (file)
@@ -454,7 +454,8 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
 DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
 
 /* Armv8.3 Pointer Authentication Registers */
-DEFINE_RENAME_SYSREG_RW_FUNCS(apgakeylo_el1, APGAKeyLo_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeyhi_el1, APIAKeyHi_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeylo_el1, APIAKeyLo_EL1)
 
 #define IS_IN_EL(x) \
        (GET_EL(read_CurrentEl()) == MODE_EL##x)
index fd7656eb5d5c820b5acc55f499a3cc23912d85b1..9817ec7fa304b95874dc6b4e984a1a1e9b90004f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -207,6 +207,8 @@ struct mmap_region;
 void setup_page_tables(const struct mmap_region *bl_regions,
                           const struct mmap_region *plat_regions);
 
+void bl_handle_pauth(void);
+
 #endif /*__ASSEMBLY__*/
 
 #endif /* BL_COMMON_H */
index 13767ff0a4b51c923d293b745555863e56875467..4832e491cd89ef7b4e3ea7a48374994db87b308a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -104,6 +104,7 @@ const char *plat_log_get_prefix(unsigned int log_level);
 void bl2_plat_preload_setup(void);
 int plat_try_next_boot_source(void);
 int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
+uint64_t *plat_init_apiakey(void);
 
 /*******************************************************************************
  * Mandatory BL1 functions
index f5fed72d065ddd56a71c5663038bef10d4781921..4489e908b0a2b784e666403543db30546ceb0a22 100644 (file)
@@ -17,6 +17,9 @@
 #if CTX_INCLUDE_PAUTH_REGS
        .global pauth_context_restore
        .global pauth_context_save
+#endif
+#if ENABLE_PAUTH
+       .global pauth_load_bl_apiakey
 #endif
        .global save_gp_registers
        .global restore_gp_registers
@@ -373,6 +376,26 @@ func pauth_context_restore
 endfunc pauth_context_restore
 #endif /* CTX_INCLUDE_PAUTH_REGS */
 
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to load the APIA key used by the firmware.
+ * -----------------------------------------------------
+ */
+#if ENABLE_PAUTH
+func pauth_load_bl_apiakey
+       /* Load instruction key A used by the Trusted Firmware. */
+       adrp    x11, plat_apiakey
+       add     x11, x11, :lo12:plat_apiakey
+       ldp     x9, x10, [x11, #0]
+
+       msr     APIAKeyLo_EL1, x9
+       msr     APIAKeyHi_EL1, x10
+
+       ret
+endfunc pauth_load_bl_apiakey
+#endif /* ENABLE_PAUTH */
+
 /* -----------------------------------------------------
  * The following functions are used to save and restore
  * all the general purpose registers. Ideally we would
index 642239771e876db890bdafc196208e20ecd0bd18..819abcd18b6e1ac92e152d1f7abb0398852cf0d5 100644 (file)
@@ -87,6 +87,9 @@ ENABLE_STACK_PROTECTOR                := 0
 # Flag to enable exception handling in EL3
 EL3_EXCEPTION_HANDLING         := 0
 
+# Flag to enable Pointer Authentication
+ENABLE_PAUTH                   := 0
+
 # Build flag to treat usage of deprecated platform and framework APIs as error.
 ERROR_DEPRECATED               := 0