diff --git a/Makefile b/Makefile index ebc8850..7b0ef5b 100644 --- a/Makefile +++ b/Makefile @@ -184,6 +184,14 @@ 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 @@ 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,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,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)) diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S index d5ecfc5..40c3191 100644 --- a/bl31/aarch64/ea_delegate.S +++ b/bl31/aarch64/ea_delegate.S @@ -68,9 +68,13 @@ /* 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 @@ /* 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 diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index cea7a8a..aa9d007 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -123,9 +123,13 @@ 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 @@ /* 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. diff --git a/common/bl_common.c b/common/bl_common.c index 84ff99c..4e76dd3 100644 --- a/common/bl_common.c +++ b/common/bl_common.c @@ -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 #include +#include #include #include #include @@ -243,3 +244,53 @@ #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 */ diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst index 808afee..ead7297 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -2566,6 +2566,11 @@ 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 ~~~~~~~ diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 7a3963b..c3df389 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -1792,6 +1792,22 @@ 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] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 70c1d5a..b420127 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -362,7 +362,7 @@ 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 @@ 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. diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h index da8b6e4..495ecb3 100644 --- a/include/arch/aarch64/arch_features.h +++ b/include/arch/aarch64/arch_features.h @@ -23,6 +23,23 @@ 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) & diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h index 4e459bb..e07db30 100644 --- a/include/arch/aarch64/arch_helpers.h +++ b/include/arch/aarch64/arch_helpers.h @@ -454,7 +454,8 @@ 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) diff --git a/include/common/bl_common.h b/include/common/bl_common.h index fd7656eb..9817ec7 100644 --- a/include/common/bl_common.h +++ b/include/common/bl_common.h @@ -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 @@ 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 */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 13767ff..4832e49 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -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 @@ 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 diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S index f5fed72..4489e90 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -18,6 +18,9 @@ .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 .global restore_gp_registers_eret @@ -374,6 +377,26 @@ #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 * only save and restore the callee saved registers when diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 6422397..819abcd 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -87,6 +87,9 @@ # 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