diff --git a/Makefile b/Makefile index 34f6890..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 ################################################################################ @@ -580,12 +597,14 @@ $(eval $(call assert_boolean,CREATE_KEYS)) $(eval $(call assert_boolean,CTX_INCLUDE_AARCH32_REGS)) $(eval $(call assert_boolean,CTX_INCLUDE_FPREGS)) +$(eval $(call assert_boolean,CTX_INCLUDE_PAUTH_REGS)) $(eval $(call assert_boolean,DEBUG)) $(eval $(call assert_boolean,DYN_DISABLE_AUTH)) $(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)) @@ -633,10 +652,12 @@ $(eval $(call add_define,COLD_BOOT_SINGLE_CPU)) $(eval $(call add_define,CTX_INCLUDE_AARCH32_REGS)) $(eval $(call add_define,CTX_INCLUDE_FPREGS)) +$(eval $(call add_define,CTX_INCLUDE_PAUTH_REGS)) $(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)) diff --git a/bl1/aarch32/bl1_entrypoint.S b/bl1/aarch32/bl1_entrypoint.S index 3f0cbaf..6a15566 100644 --- a/bl1/aarch32/bl1_entrypoint.S +++ b/bl1/aarch32/bl1_entrypoint.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -52,12 +52,10 @@ _exception_vectors=bl1_vector_table /* ----------------------------------------------------- - * Perform early platform setup & platform - * specific early arch. setup e.g. mmu setup + * Perform BL1 setup * ----------------------------------------------------- */ - bl bl1_early_platform_setup - bl bl1_plat_arch_setup + bl bl1_setup /* ----------------------------------------------------- * Jump to main function. diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S index f7e02e9..0f8d5aa 100644 --- a/bl1/aarch64/bl1_entrypoint.S +++ b/bl1/aarch64/bl1_entrypoint.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -32,24 +32,42 @@ _init_c_runtime=1 \ _exception_vectors=bl1_exceptions - /* --------------------------------------------- - * Architectural init. can be generic e.g. - * enabling stack alignment and platform spec- - * ific e.g. MMU & page table setup as per the - * platform memory map. Perform the latter here - * and the former in bl1_main. - * --------------------------------------------- + /* -------------------------------------------------------------------- + * Perform BL1 setup + * -------------------------------------------------------------------- */ - bl bl1_early_platform_setup - bl bl1_plat_arch_setup + bl bl1_setup - /* -------------------------------------------------- + /* -------------------------------------------------------------------- + * Enable pointer authentication + * -------------------------------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el3 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb +#endif /* ENABLE_PAUTH */ + + /* -------------------------------------------------------------------- * Initialize platform and jump to our c-entry point * for this type of reset. - * -------------------------------------------------- + * -------------------------------------------------------------------- */ bl bl1_main + /* -------------------------------------------------------------------- + * Disable pointer authentication before jumping to BL31 or that will + * cause an authentication failure during the early platform init. + * -------------------------------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el3 + bic x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb +#endif /* ENABLE_PAUTH */ + /* -------------------------------------------------- * Do the transition to next boot image. * -------------------------------------------------- diff --git a/bl1/bl1.mk b/bl1/bl1.mk index ec7d728..7f1a823 100644 --- a/bl1/bl1.mk +++ b/bl1/bl1.mk @@ -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 # @@ -21,6 +21,10 @@ lib/el3_runtime/aarch64/context.S endif +ifeq (${ENABLE_PAUTH},1) +BL1_CFLAGS += -msign-return-address=non-leaf +endif + ifeq (${TRUSTED_BOARD_BOOT},1) BL1_SOURCES += bl1/bl1_fwu.c endif diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index d2c2b41..fce14f5 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.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 */ @@ -52,6 +52,28 @@ } /******************************************************************************* + * Setup function for BL1. + ******************************************************************************/ +void bl1_setup(void) +{ + /* Perform early platform-specific setup */ + bl1_early_platform_setup(); + +#ifdef AARCH64 + /* + * Update pointer authentication key before the MMU is enabled. It is + * saved in the rodata section, that can be writen before enabling the + * MMU. This function must be called after the console is initialized + * in the early platform setup. + */ + bl_handle_pauth(); +#endif /* AARCH64 */ + + /* Perform late platform-specific setup */ + bl1_plat_arch_setup(); +} + +/******************************************************************************* * Function to perform late architectural and platform specific initialization. * It also queries the platform to load and run next BL image. Only called * by the primary cpu after a cold boot. diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S index cc846dd..35da133 100644 --- a/bl2/aarch32/bl2_el3_entrypoint.S +++ b/bl2/aarch32/bl2_el3_entrypoint.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -36,8 +36,11 @@ mov r2, r11 mov r3, r12 - bl bl2_el3_early_platform_setup - bl bl2_el3_plat_arch_setup + /* --------------------------------------------- + * Perform BL2 setup + * --------------------------------------------- + */ + bl bl2_el3_setup /* --------------------------------------------- * Jump to main function. diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S index e7b98af..23d1513 100644 --- a/bl2/aarch32/bl2_entrypoint.S +++ b/bl2/aarch32/bl2_entrypoint.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -108,16 +108,15 @@ #endif /* --------------------------------------------- - * Perform early platform setup & platform - * specific early arch. setup e.g. mmu setup + * Perform BL2 setup * --------------------------------------------- */ mov r0, r9 mov r1, r10 mov r2, r11 mov r3, r12 - bl bl2_early_platform_setup2 - bl bl2_plat_arch_setup + + bl bl2_setup /* --------------------------------------------- * Jump to main function. diff --git a/bl2/aarch64/bl2_el3_entrypoint.S b/bl2/aarch64/bl2_el3_entrypoint.S index 16b7c0d..d1e4247 100644 --- a/bl2/aarch64/bl2_el3_entrypoint.S +++ b/bl2/aarch64/bl2_el3_entrypoint.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -29,16 +29,31 @@ _init_c_runtime=1 \ _exception_vectors=bl2_el3_exceptions - /* + /* --------------------------------------------- * Restore parameters of boot rom + * --------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 - bl bl2_el3_early_platform_setup - bl bl2_el3_plat_arch_setup + /* --------------------------------------------- + * Perform BL2 setup + * --------------------------------------------- + */ + bl bl2_el3_setup + + /* --------------------------------------------- + * Enable pointer authentication + * --------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el3 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb +#endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. @@ -55,16 +70,29 @@ func bl2_run_next_image mov x20,x0 - /* - * MMU needs to be disabled because both BL2 and BL31 execute - * in EL3, and therefore share the same address space. - * BL31 will initialize the address space according to its - * own requirement. - */ + /* --------------------------------------------- + * MMU needs to be disabled because both BL2 and BL31 execute + * in EL3, and therefore share the same address space. + * BL31 will initialize the address space according to its + * own requirement. + * --------------------------------------------- + */ bl disable_mmu_icache_el3 tlbi alle3 bl bl2_el3_plat_prepare_exit + /* --------------------------------------------- + * Disable pointer authentication before jumping to BL31 or that will + * cause an authentication failure during the early platform init. + * --------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el3 + bic x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb +#endif /* ENABLE_PAUTH */ + ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 msr spsr_el3, x1 diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S index d938947..611b807 100644 --- a/bl2/aarch64/bl2_entrypoint.S +++ b/bl2/aarch64/bl2_entrypoint.S @@ -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 */ @@ -106,17 +106,25 @@ #endif /* --------------------------------------------- - * Perform early platform setup & platform - * specific early arch. setup e.g. mmu setup + * Perform BL2 setup * --------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 - bl bl2_early_platform_setup2 + bl bl2_setup - bl bl2_plat_arch_setup + /* --------------------------------------------- + * Enable pointer authentication + * --------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el1 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el1, x0 + isb +#endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. diff --git a/bl2/bl2.mk b/bl2/bl2.mk index f905bc2..9523918 100644 --- a/bl2/bl2.mk +++ b/bl2/bl2.mk @@ -1,10 +1,11 @@ # -# 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 # -BL2_SOURCES += bl2/bl2_main.c \ +BL2_SOURCES += bl2/bl2_image_load_v2.c \ + bl2/bl2_main.c \ bl2/${ARCH}/bl2_arch_setup.c \ lib/locks/exclusive/${ARCH}/spinlock.S \ plat/common/${ARCH}/platform_up_stack.S \ @@ -14,7 +15,9 @@ BL2_SOURCES += common/aarch64/early_exceptions.S endif -BL2_SOURCES += bl2/bl2_image_load_v2.c +ifeq (${ENABLE_PAUTH},1) +BL2_CFLAGS += -msign-return-address=non-leaf +endif ifeq (${BL2_AT_EL3},0) BL2_SOURCES += bl2/${ARCH}/bl2_entrypoint.S diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index 019088d..7d8d60c 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.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 */ @@ -21,6 +21,55 @@ #define NEXT_IMAGE "BL31" #endif +#if !BL2_AT_EL3 +/******************************************************************************* + * Setup function for BL2. + ******************************************************************************/ +void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3) +{ + /* Perform early platform-specific setup */ + bl2_early_platform_setup2(arg0, arg1, arg2, arg3); + +#ifdef AARCH64 + /* + * Update pointer authentication key before the MMU is enabled. It is + * saved in the rodata section, that can be writen before enabling the + * MMU. This function must be called after the console is initialized + * in the early platform setup. + */ + bl_handle_pauth(); +#endif /* AARCH64 */ + + /* Perform late platform-specific setup */ + bl2_plat_arch_setup(); +} + +#else /* if BL2_AT_EL3 */ +/******************************************************************************* + * Setup function for BL2 when BL2_AT_EL3=1. + ******************************************************************************/ +void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3) +{ + /* Perform early platform-specific setup */ + bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3); + +#ifdef AARCH64 + /* + * Update pointer authentication key before the MMU is enabled. It is + * saved in the rodata section, that can be writen before enabling the + * MMU. This function must be called after the console is initialized + * in the early platform setup. + */ + bl_handle_pauth(); +#endif /* AARCH64 */ + + /* Perform late platform-specific setup */ + bl2_el3_plat_arch_setup(); +} +#endif /* BL2_AT_EL3 */ + /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to * next BL. The memory occupied by BL2 will be reclaimed by BL3x stages. BL2 @@ -65,11 +114,11 @@ * be passed to next BL image as an argument. */ smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0); -#else +#else /* if BL2_AT_EL3 */ NOTICE("BL2: Booting " NEXT_IMAGE "\n"); print_entry_point_info(next_bl_ep_info); console_flush(); bl2_run_next_image(next_bl_ep_info); -#endif +#endif /* BL2_AT_EL3 */ } diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index c41773b..8e9528b 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -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 */ @@ -87,29 +87,39 @@ bl fixup_gdt_reloc #endif /* ENABLE_PIE */ - /* --------------------------------------------- - * Perform platform specific early arch. setup - * --------------------------------------------- + /* -------------------------------------------------------------------- + * Perform BL31 setup + * -------------------------------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 - bl bl31_early_platform_setup2 - bl bl31_plat_arch_setup + bl bl31_setup - /* --------------------------------------------- + /* -------------------------------------------------------------------- + * Enable pointer authentication + * -------------------------------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el3 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el3, x0 + isb +#endif /* ENABLE_PAUTH */ + + /* -------------------------------------------------------------------- * Jump to main function. - * --------------------------------------------- + * -------------------------------------------------------------------- */ bl bl31_main - /* ------------------------------------------------------------- + /* -------------------------------------------------------------------- * Clean the .data & .bss sections to main memory. This ensures * that any global data which was initialised by the primary CPU * is visible to secondary CPUs before they enable their data * caches and participate in coherency. - * ------------------------------------------------------------- + * -------------------------------------------------------------------- */ adr x0, __DATA_START__ adr x1, __DATA_END__ diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S index 0c8cfa8..40c3191 100644 --- a/bl31/aarch64/ea_delegate.S +++ b/bl31/aarch64/ea_delegate.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -68,6 +68,14 @@ /* 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 mrs x1, esr_el3 @@ -98,6 +106,14 @@ /* 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 mrs x1, esr_el3 diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index 4f53b8e..aa9d007 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -120,7 +120,17 @@ * --------------------------------------------------------------------- */ .macro handle_interrupt_exception label + 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 mrs x1, elr_el3 @@ -320,14 +330,25 @@ tbnz x0, #FUNCID_CC_SHIFT, smc_prohibited smc_handler64: + /* NOTE: The code below must preserve x0-x4 */ + + /* 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. * We already have x0-x4 in place. x5 will point to a cookie (not used * now). x6 will point to the context structure (SP_EL3) and x7 will * contain flags we need to pass to the handler. */ - bl save_gp_registers - mov x5, xzr mov x6, sp diff --git a/bl31/bl31.mk b/bl31/bl31.mk index c9ba926..10feae1 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -75,6 +75,10 @@ BL31_SOURCES += lib/extensions/mpam/mpam.c endif +ifeq (${ENABLE_PAUTH},1) +BL31_CFLAGS += -msign-return-address=non-leaf +endif + ifeq (${WORKAROUND_CVE_2017_5715},1) BL31_SOURCES += lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S \ lib/cpus/aarch64/wa_cve_2017_5715_mmu.S diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index da35f75..aca16d6 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -64,6 +64,27 @@ } /******************************************************************************* + * Setup function for BL31. + ******************************************************************************/ +void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3) +{ + /* Perform early platform-specific setup */ + bl31_early_platform_setup2(arg0, arg1, arg2, arg3); + + /* + * Update pointer authentication key before the MMU is enabled. It is + * saved in the rodata section, that can be writen before enabling the + * MMU. This function must be called after the console is initialized + * in the early platform setup. + */ + bl_handle_pauth(); + + /* Perform late platform-specific setup */ + bl31_plat_arch_setup(); +} + +/******************************************************************************* * BL31 is responsible for setting up the runtime services for the primary cpu * before passing control to the bootloader or an Operating System. This * function calls runtime_svc_init() which initializes all registered runtime diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S index 48f6981..710b458 100644 --- a/bl32/tsp/aarch64/tsp_entrypoint.S +++ b/bl32/tsp/aarch64/tsp_entrypoint.S @@ -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 */ @@ -122,12 +122,21 @@ #endif /* --------------------------------------------- - * Perform early platform setup & platform - * specific early arch. setup e.g. mmu setup + * Perform TSP setup * --------------------------------------------- */ - bl tsp_early_platform_setup - bl tsp_plat_arch_setup + bl tsp_setup + + /* --------------------------------------------- + * Enable pointer authentication + * --------------------------------------------- + */ +#if ENABLE_PAUTH + mrs x0, sctlr_el1 + orr x0, x0, #SCTLR_EnIA_BIT + msr sctlr_el1, x0 + isb +#endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk index 4ea3dfb..b1fe7ff 100644 --- a/bl32/tsp/tsp.mk +++ b/bl32/tsp/tsp.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # @@ -17,6 +17,11 @@ BL32_LINKERFILE := bl32/tsp/tsp.ld.S +# This flag determines whether pointer authentication is used in the TSP or not +ifeq ($(ENABLE_PAUTH),1) +BL32_CFLAGS += -msign-return-address=non-leaf +endif + # This flag determines if the TSPD initializes BL32 in tspd_init() (synchronous # method) or configures BL31 to pass control to BL32 instead of BL33 # (asynchronous method). diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c index 407ed47..30bf6ff 100644 --- a/bl32/tsp/tsp_main.c +++ b/bl32/tsp/tsp_main.c @@ -72,6 +72,26 @@ } /******************************************************************************* + * Setup function for TSP. + ******************************************************************************/ +void tsp_setup(void) +{ + /* Perform early platform-specific setup */ + tsp_early_platform_setup(); + + /* + * Update pointer authentication key before the MMU is enabled. It is + * saved in the rodata section, that can be writen before enabling the + * MMU. This function must be called after the console is initialized + * in the early platform setup. + */ + bl_handle_pauth(); + + /* Perform late platform-specific setup */ + tsp_plat_arch_setup(); +} + +/******************************************************************************* * TSP main entry point where it gets the opportunity to initialize its secure * state/applications. Once the state is initialized, it must return to the * SPD with a pointer to the 'tsp_vector_table' jump table. 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 299654f..ead7297 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -2558,8 +2558,18 @@ Armv8.3-A ~~~~~~~~~ -- Pointer Authentication features of Armv8.3-A are unconditionally enabled so - that lower ELs are allowed to use them without causing a trap to EL3. +- Pointer authentication features of Armv8.3-A are unconditionally enabled in + the Non-secure world so that lower ELs are allowed to use them without + causing a trap to EL3. + + In order to enable the Secure world to use it, ``CTX_INCLUDE_PAUTH_REGS`` + 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 4ff1c72..b420127 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -358,6 +358,12 @@ registers to be included when saving and restoring the CPU context. Default is 0. +- ``CTX_INCLUDE_PAUTH_REGS``: Boolean option that, when set to 1, will cause + 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 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. @@ -405,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.h b/include/arch/aarch64/arch.h index c65b3a3..b9d1f9f 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -154,26 +154,22 @@ #define ID_AA64PFR0_GIC_SHIFT U(24) #define ID_AA64PFR0_GIC_WIDTH U(4) -#define ID_AA64PFR0_GIC_MASK ((ULL(1) << ID_AA64PFR0_GIC_WIDTH) - ULL(1)) +#define ID_AA64PFR0_GIC_MASK ULL(0xf) /* ID_AA64ISAR1_EL1 definitions */ +#define ID_AA64ISAR1_EL1 S3_0_C0_C6_1 #define ID_AA64ISAR1_GPI_SHIFT U(28) #define ID_AA64ISAR1_GPI_WIDTH U(4) +#define ID_AA64ISAR1_GPI_MASK ULL(0xf) #define ID_AA64ISAR1_GPA_SHIFT U(24) #define ID_AA64ISAR1_GPA_WIDTH U(4) +#define ID_AA64ISAR1_GPA_MASK ULL(0xf) #define ID_AA64ISAR1_API_SHIFT U(8) #define ID_AA64ISAR1_API_WIDTH U(4) +#define ID_AA64ISAR1_API_MASK ULL(0xf) #define ID_AA64ISAR1_APA_SHIFT U(4) #define ID_AA64ISAR1_APA_WIDTH U(4) - -#define ID_AA64ISAR1_GPI_MASK \ - (((ULL(1) << ID_AA64ISAR1_GPI_WIDTH) - ULL(1)) << ID_AA64ISAR1_GPI_SHIFT) -#define ID_AA64ISAR1_GPA_MASK \ - (((ULL(1) << ID_AA64ISAR1_GPA_WIDTH) - ULL(1)) << ID_AA64ISAR1_GPA_SHIFT) -#define ID_AA64ISAR1_API_MASK \ - (((ULL(1) << ID_AA64ISAR1_API_WIDTH) - ULL(1)) << ID_AA64ISAR1_API_SHIFT) -#define ID_AA64ISAR1_APA_MASK \ - (((ULL(1) << ID_AA64ISAR1_APA_WIDTH) - ULL(1)) << ID_AA64ISAR1_APA_SHIFT) +#define ID_AA64ISAR1_APA_MASK ULL(0xf) /* ID_AA64MMFR0_EL1 definitions */ #define ID_AA64MMFR0_EL1_PARANGE_SHIFT U(0) @@ -258,9 +254,7 @@ #define SCTLR_E0E_BIT (ULL(1) << 24) #define SCTLR_EE_BIT (ULL(1) << 25) #define SCTLR_UCI_BIT (ULL(1) << 26) -#define SCTLR_TRE_BIT (ULL(1) << 28) -#define SCTLR_AFE_BIT (ULL(1) << 29) -#define SCTLR_TE_BIT (ULL(1) << 30) +#define SCTLR_EnIA_BIT (ULL(1) << 31) #define SCTLR_DSSBS_BIT (ULL(1) << 44) #define SCTLR_RESET_VAL SCTLR_EL3_RES1 @@ -823,7 +817,16 @@ /******************************************************************************* * Armv8.3 Pointer Authentication Registers ******************************************************************************/ +#define APIAKeyLo_EL1 S3_0_C2_C1_0 +#define APIAKeyHi_EL1 S3_0_C2_C1_1 +#define APIBKeyLo_EL1 S3_0_C2_C1_2 +#define APIBKeyHi_EL1 S3_0_C2_C1_3 +#define APDAKeyLo_EL1 S3_0_C2_C2_0 +#define APDAKeyHi_EL1 S3_0_C2_C2_1 +#define APDBKeyLo_EL1 S3_0_C2_C2_2 +#define APDBKeyHi_EL1 S3_0_C2_C2_3 #define APGAKeyLo_EL1 S3_0_C2_C3_0 +#define APGAKeyHi_EL1 S3_0_C2_C3_1 /******************************************************************************* * Armv8.4 Data Independent Timing Registers 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/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S index 5f5e0c6..22b32b4 100644 --- a/include/arch/aarch64/el3_common_macros.S +++ b/include/arch/aarch64/el3_common_macros.S @@ -76,9 +76,16 @@ * authentication instructions from lower ELs. * --------------------------------------------------------------------- */ - mov_imm x0, ((SCR_RESET_VAL | SCR_EA_BIT | SCR_SIF_BIT | \ - SCR_API_BIT | SCR_APK_BIT) \ + mov_imm x0, ((SCR_RESET_VAL | SCR_EA_BIT | SCR_SIF_BIT) \ & ~(SCR_TWE_BIT | SCR_TWI_BIT | SCR_SMD_BIT)) +#if CTX_INCLUDE_PAUTH_REGS + /* + * If the pointer authentication registers are saved during world + * switches, enable pointer authentication everywhere, as it is safe to + * do so. + */ + orr x0, x0, #(SCR_API_BIT | SCR_APK_BIT) +#endif msr scr_el3, x0 /* --------------------------------------------------------------------- diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h index 7b5d875..937b8c7 100644 --- a/include/bl1/bl1.h +++ b/include/bl1/bl1.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -83,6 +83,7 @@ void bl1_print_next_bl_ep_info(const struct entry_point_info *bl_ep_info); +void bl1_setup(void); void bl1_main(void); void bl1_plat_prepare_exit(entry_point_info_t *ep_info); diff --git a/include/bl2/bl2.h b/include/bl2/bl2.h index 8ec080c..73f5ac7 100644 --- a/include/bl2/bl2.h +++ b/include/bl2/bl2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,6 +7,12 @@ #ifndef BL2_H #define BL2_H +#include + +void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3); +void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3); void bl2_main(void); #endif /* BL2_H */ diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h index 08c555d..3deb0a5 100644 --- a/include/bl31/bl31.h +++ b/include/bl31/bl31.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 */ @@ -12,6 +12,8 @@ /******************************************************************************* * Function prototypes ******************************************************************************/ +void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, + u_register_t arg3); void bl31_next_el_arch_setup(uint32_t security_state); void bl31_set_next_image_type(uint32_t security_state); uint32_t bl31_get_next_image_type(void); diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h index ed4792e..18d3079 100644 --- a/include/bl32/tsp/tsp.h +++ b/include/bl32/tsp/tsp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, 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 @@ tsp_vector_isn_t abort_yield_smc_entry; } tsp_vectors_t; +void tsp_setup(void); #endif /* __ASSEMBLY__ */ 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/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h index 70c50aa..5bd0de4 100644 --- a/include/lib/el3_runtime/aarch64/context.h +++ b/include/lib/el3_runtime/aarch64/context.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,25 +104,30 @@ #define CTX_SPSR_FIQ U(0xd8) #define CTX_DACR32_EL2 U(0xe0) #define CTX_IFSR32_EL2 U(0xe8) -#define CTX_TIMER_SYSREGS_OFF U(0xf0) /* Align to the next 16 byte boundary */ +#define CTX_AARCH32_END U(0xf0) /* Align to the next 16 byte boundary */ #else -#define CTX_TIMER_SYSREGS_OFF U(0xc0) /* Align to the next 16 byte boundary */ -#endif /* __CTX_INCLUDE_AARCH32_REGS__ */ +#define CTX_AARCH32_END U(0xc0) /* Align to the next 16 byte boundary */ +#endif /* CTX_INCLUDE_AARCH32_REGS */ /* * If the timer registers aren't saved and restored, we don't have to reserve * space for them in the context */ #if NS_TIMER_SWITCH -#define CTX_CNTP_CTL_EL0 (CTX_TIMER_SYSREGS_OFF + U(0x0)) -#define CTX_CNTP_CVAL_EL0 (CTX_TIMER_SYSREGS_OFF + U(0x8)) -#define CTX_CNTV_CTL_EL0 (CTX_TIMER_SYSREGS_OFF + U(0x10)) -#define CTX_CNTV_CVAL_EL0 (CTX_TIMER_SYSREGS_OFF + U(0x18)) -#define CTX_CNTKCTL_EL1 (CTX_TIMER_SYSREGS_OFF + U(0x20)) -#define CTX_SYSREGS_END (CTX_TIMER_SYSREGS_OFF + U(0x30)) /* Align to the next 16 byte boundary */ +#define CTX_CNTP_CTL_EL0 (CTX_AARCH32_END + U(0x0)) +#define CTX_CNTP_CVAL_EL0 (CTX_AARCH32_END + U(0x8)) +#define CTX_CNTV_CTL_EL0 (CTX_AARCH32_END + U(0x10)) +#define CTX_CNTV_CVAL_EL0 (CTX_AARCH32_END + U(0x18)) +#define CTX_CNTKCTL_EL1 (CTX_AARCH32_END + U(0x20)) +#define CTX_TIMER_SYSREGS_END (CTX_AARCH32_END + U(0x30)) /* Align to the next 16 byte boundary */ #else -#define CTX_SYSREGS_END CTX_TIMER_SYSREGS_OFF -#endif /* __NS_TIMER_SWITCH__ */ +#define CTX_TIMER_SYSREGS_END CTX_AARCH32_END +#endif /* NS_TIMER_SWITCH */ + +/* + * End of system registers. + */ +#define CTX_SYSREGS_END CTX_TIMER_SYSREGS_END /******************************************************************************* * Constants that allow assembler code to access members of and the 'fp_regs' @@ -174,16 +179,38 @@ #define CTX_FPREGS_END U(0) #endif +/******************************************************************************* + * Registers related to CVE-2018-3639 + ******************************************************************************/ #define CTX_CVE_2018_3639_OFFSET (CTX_FPREGS_OFFSET + CTX_FPREGS_END) #define CTX_CVE_2018_3639_DISABLE U(0) #define CTX_CVE_2018_3639_END U(0x10) /* Align to the next 16 byte boundary */ +/******************************************************************************* + * Registers related to ARMv8.3-PAuth. + ******************************************************************************/ +#define CTX_PAUTH_REGS_OFFSET (CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_END) +#if CTX_INCLUDE_PAUTH_REGS +#define CTX_PACIAKEY_LO U(0x0) +#define CTX_PACIAKEY_HI U(0x8) +#define CTX_PACIBKEY_LO U(0x10) +#define CTX_PACIBKEY_HI U(0x18) +#define CTX_PACDAKEY_LO U(0x20) +#define CTX_PACDAKEY_HI U(0x28) +#define CTX_PACDBKEY_LO U(0x30) +#define CTX_PACDBKEY_HI U(0x38) +#define CTX_PACGAKEY_LO U(0x40) +#define CTX_PACGAKEY_HI U(0x48) +#define CTX_PACGAKEY_END U(0x50) +#define CTX_PAUTH_REGS_END U(0x60) /* Align to the next 16 byte boundary */ +#else +#define CTX_PAUTH_REGS_END U(0) +#endif /* CTX_INCLUDE_PAUTH_REGS */ + #ifndef __ASSEMBLY__ #include -#include /* for CACHE_WRITEBACK_GRANULE */ - #include /* @@ -200,10 +227,13 @@ #define CTX_GPREG_ALL (CTX_GPREGS_END >> DWORD_SHIFT) #define CTX_SYSREG_ALL (CTX_SYSREGS_END >> DWORD_SHIFT) #if CTX_INCLUDE_FPREGS -#define CTX_FPREG_ALL (CTX_FPREGS_END >> DWORD_SHIFT) +# define CTX_FPREG_ALL (CTX_FPREGS_END >> DWORD_SHIFT) #endif #define CTX_EL3STATE_ALL (CTX_EL3STATE_END >> DWORD_SHIFT) #define CTX_CVE_2018_3639_ALL (CTX_CVE_2018_3639_END >> DWORD_SHIFT) +#if CTX_INCLUDE_PAUTH_REGS +# define CTX_PAUTH_REGS_ALL (CTX_PAUTH_REGS_END >> DWORD_SHIFT) +#endif /* * AArch64 general purpose register context structure. Usually x0-x18, @@ -239,6 +269,11 @@ /* Function pointer used by CVE-2018-3639 dynamic mitigation */ DEFINE_REG_STRUCT(cve_2018_3639, CTX_CVE_2018_3639_ALL); +/* Registers associated to ARMv8.3-PAuth */ +#if CTX_INCLUDE_PAUTH_REGS +DEFINE_REG_STRUCT(pauth, CTX_PAUTH_REGS_ALL); +#endif + /* * Macros to access members of any of the above structures using their * offsets @@ -264,16 +299,22 @@ fp_regs_t fpregs_ctx; #endif cve_2018_3639_t cve_2018_3639_ctx; +#if CTX_INCLUDE_PAUTH_REGS + pauth_t pauth_ctx; +#endif } cpu_context_t; /* Macros to access members of the 'cpu_context_t' structure */ #define get_el3state_ctx(h) (&((cpu_context_t *) h)->el3state_ctx) #if CTX_INCLUDE_FPREGS -#define get_fpregs_ctx(h) (&((cpu_context_t *) h)->fpregs_ctx) +# define get_fpregs_ctx(h) (&((cpu_context_t *) h)->fpregs_ctx) #endif #define get_sysregs_ctx(h) (&((cpu_context_t *) h)->sysregs_ctx) #define get_gpregs_ctx(h) (&((cpu_context_t *) h)->gpregs_ctx) #define get_cve_2018_3639_ctx(h) (&((cpu_context_t *) h)->cve_2018_3639_ctx) +#if CTX_INCLUDE_PAUTH_REGS +# define get_pauth_ctx(h) (&((cpu_context_t *) h)->pauth_ctx) +#endif /* * Compile time assertions related to the 'cpu_context' structure to @@ -292,6 +333,10 @@ assert_core_context_el3state_offset_mismatch); CASSERT(CTX_CVE_2018_3639_OFFSET == __builtin_offsetof(cpu_context_t, cve_2018_3639_ctx), \ assert_core_context_cve_2018_3639_offset_mismatch); +#if CTX_INCLUDE_PAUTH_REGS +CASSERT(CTX_PAUTH_REGS_OFFSET == __builtin_offsetof(cpu_context_t, pauth_ctx), \ + assert_core_context_pauth_offset_mismatch); +#endif /* * Helper macro to set the general purpose registers that correspond to @@ -339,14 +384,6 @@ void fpregs_context_restore(fp_regs_t *regs); #endif - -#undef CTX_SYSREG_ALL -#if CTX_INCLUDE_FPREGS -#undef CTX_FPREG_ALL -#endif -#undef CTX_GPREG_ALL -#undef CTX_EL3STATE_ALL - #endif /* __ASSEMBLY__ */ #endif /* CONTEXT_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 707e6db..4489e90 100644 --- a/lib/el3_runtime/aarch64/context.S +++ b/lib/el3_runtime/aarch64/context.S @@ -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 */ @@ -14,6 +14,13 @@ .global fpregs_context_save .global fpregs_context_restore #endif +#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 .global restore_gp_registers_eret @@ -299,6 +306,96 @@ endfunc fpregs_context_restore #endif /* CTX_INCLUDE_FPREGS */ +#if CTX_INCLUDE_PAUTH_REGS +/* ----------------------------------------------------- + * The following function strictly follows the AArch64 + * PCS to use x9-x17 (temporary caller-saved registers) + * to save the ARMv8.3-PAuth register context. It assumes + * that 'sp' is pointing to a 'cpu_context_t' structure + * to where the register context will be saved. + * ----------------------------------------------------- + */ +func pauth_context_save + add x11, sp, #CTX_PAUTH_REGS_OFFSET + + mrs x9, APIAKeyLo_EL1 + mrs x10, APIAKeyHi_EL1 + stp x9, x10, [x11, #CTX_PACIAKEY_LO] + + mrs x9, APIBKeyLo_EL1 + mrs x10, APIBKeyHi_EL1 + stp x9, x10, [x11, #CTX_PACIBKEY_LO] + + mrs x9, APDAKeyLo_EL1 + mrs x10, APDAKeyHi_EL1 + stp x9, x10, [x11, #CTX_PACDAKEY_LO] + + mrs x9, APDBKeyLo_EL1 + mrs x10, APDBKeyHi_EL1 + stp x9, x10, [x11, #CTX_PACDBKEY_LO] + + mrs x9, APGAKeyLo_EL1 + mrs x10, APGAKeyHi_EL1 + stp x9, x10, [x11, #CTX_PACGAKEY_LO] + + ret +endfunc pauth_context_save + +/* ----------------------------------------------------- + * The following function strictly follows the AArch64 + * PCS to use x9-x17 (temporary caller-saved registers) + * to restore the ARMv8.3-PAuth register context. It assumes + * that 'sp' is pointing to a 'cpu_context_t' structure + * from where the register context will be restored. + * ----------------------------------------------------- + */ +func pauth_context_restore + add x11, sp, #CTX_PAUTH_REGS_OFFSET + + ldp x9, x10, [x11, #CTX_PACIAKEY_LO] + msr APIAKeyLo_EL1, x9 + msr APIAKeyHi_EL1, x10 + + ldp x9, x10, [x11, #CTX_PACIAKEY_LO] + msr APIBKeyLo_EL1, x9 + msr APIBKeyHi_EL1, x10 + + ldp x9, x10, [x11, #CTX_PACDAKEY_LO] + msr APDAKeyLo_EL1, x9 + msr APDAKeyHi_EL1, x10 + + ldp x9, x10, [x11, #CTX_PACDBKEY_LO] + msr APDBKeyLo_EL1, x9 + msr APDBKeyHi_EL1, x10 + + ldp x9, x10, [x11, #CTX_PACGAKEY_LO] + msr APGAKeyLo_EL1, x9 + msr APGAKeyHi_EL1, x10 + + ret +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 @@ -332,9 +429,10 @@ ret endfunc save_gp_registers -/* +/* ----------------------------------------------------- * This function restores all general purpose registers except x30 from the * CPU context. x30 register must be explicitly restored by the caller. + * ----------------------------------------------------- */ func restore_gp_registers ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] @@ -357,9 +455,10 @@ ret endfunc restore_gp_registers -/* +/* ----------------------------------------------------- * Restore general purpose registers (including x30), and exit EL3 via. ERET to * a lower exception level. + * ----------------------------------------------------- */ func restore_gp_registers_eret bl restore_gp_registers @@ -377,12 +476,12 @@ eret endfunc restore_gp_registers_eret - /* ----------------------------------------------------- - * This routine assumes that the SP_EL3 is pointing to - * a valid context structure from where the gp regs and - * other special registers can be retrieved. - * ----------------------------------------------------- - */ +/* ----------------------------------------------------- + * This routine assumes that the SP_EL3 is pointing to + * a valid context structure from where the gp regs and + * other special registers can be retrieved. + * ----------------------------------------------------- + */ func el3_exit /* ----------------------------------------------------- * Save the current SP_EL0 i.e. the EL3 runtime stack @@ -410,9 +509,14 @@ cmp x17, xzr beq 1f blr x17 +1: #endif -1: +#if CTX_INCLUDE_PAUTH_REGS + /* Restore ARMv8.3-PAuth registers */ + bl pauth_context_restore +#endif + /* Restore saved general purpose registers and return */ b restore_gp_registers_eret endfunc el3_exit diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c index b956491..83f6e48 100644 --- a/lib/el3_runtime/aarch64/context_mgmt.c +++ b/lib/el3_runtime/aarch64/context_mgmt.c @@ -122,6 +122,20 @@ scr_el3 |= SCR_FIEN_BIT; #endif +#if !CTX_INCLUDE_PAUTH_REGS + /* + * If the pointer authentication registers aren't saved during world + * switches the value of the registers can be leaked from the Secure to + * the Non-secure world. To prevent this, rather than enabling pointer + * authentication everywhere, we only enable it in the Non-secure world. + * + * If the Secure world wants to use pointer authentication, + * CTX_INCLUDE_PAUTH_REGS must be set to 1. + */ + if (security_state == NON_SECURE) + scr_el3 |= SCR_API_BIT | SCR_APK_BIT; +#endif /* !CTX_INCLUDE_PAUTH_REGS */ + #ifdef IMAGE_BL31 /* * SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 76a9fd4..819abcd 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -51,6 +51,11 @@ # Include FP registers in cpu context CTX_INCLUDE_FPREGS := 0 +# Include pointer authentication (ARMv8.3-PAuth) registers in cpu context. This +# must be set to 1 if the platform wants to use this feature in the Secure +# world. It is not needed to use it in the Non-secure world. +CTX_INCLUDE_PAUTH_REGS := 0 + # Debug build DEBUG := 0 @@ -82,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 diff --git a/plat/arm/common/aarch64/arm_pauth.c b/plat/arm/common/aarch64/arm_pauth.c new file mode 100644 index 0000000..c847119 --- /dev/null +++ b/plat/arm/common/aarch64/arm_pauth.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +/* + * Instruction pointer authentication key A. The low 64-bit are at [0], and the + * high bits at [1]. They are run-time constants so they are placed in the + * rodata section. They are written before MMU is turned on and the permissions + * are effective. + */ +uint64_t plat_apiakey[2] __section("rodata.apiakey"); + +/* + * This is only a toy implementation to generate a seemingly random 128-bit key + * from sp and x30 values. A production system must re-implement this function + * to generate keys from a reliable randomness source. + */ +uint64_t *plat_init_apiakey(void) +{ + uintptr_t return_addr = (uintptr_t)__builtin_return_address(0U); + uintptr_t frame_addr = (uintptr_t)__builtin_frame_address(0U); + + plat_apiakey[0] = (return_addr << 13) ^ frame_addr; + plat_apiakey[1] = (frame_addr << 15) ^ return_addr; + + return plat_apiakey; +} diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index f18a9af..5e890ed 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -236,6 +236,11 @@ lib/extensions/ras/ras_common.c endif +# Pointer Authentication sources +ifeq (${ENABLE_PAUTH}, 1) +PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c +endif + # SPM uses libfdt in Arm platforms ifeq (${SPM_MM},0) ifeq (${ENABLE_SPM},1)