feat(cpufeat): enable FEAT_PAuth to FEAT_STATE_CHECKED

FEAT_PAuth is the second to last feature to be a boolean choice - it's
either unconditionally compiled in and must be present in hardware or
it's not compiled in. FEAT_PAuth is architected to be backwards
compatible - a subset of the branch guarding instructions (pacia/autia)
execute as NOPs when PAuth is not present. That subset is used with
`-mbranch-protection=standard` and -march pre-8.3. This patch adds the
necessary logic to also check accesses of the non-backward compatible
registers and allow a fully checked implementation.

Note that a checked support requires -march to be pre 8.3, as otherwise
the compiler will include branch protection instructions that are not
NOPs without PAuth (eg retaa) which cannot be checked.

Change-Id: Id942c20cae9d15d25b3d72b8161333642574ddaa
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
This commit is contained in:
Boyan Karatotev 2025-04-02 11:16:18 +01:00
parent 51997e3d8a
commit 8d9f5f2586
11 changed files with 124 additions and 63 deletions

View File

@ -491,6 +491,12 @@ endif #(SPD=none)
################################################################################ ################################################################################
include ${PLAT_MAKEFILE_FULL} include ${PLAT_MAKEFILE_FULL}
################################################################################
# Setup arch_features based on ARM_ARCH_MAJOR, ARM_ARCH_MINOR provided from
# platform.
################################################################################
include ${MAKE_HELPERS_DIRECTORY}arch_features.mk
################################################################################ ################################################################################
# Process BRANCH_PROTECTION value and set # Process BRANCH_PROTECTION value and set
# Pointer Authentication and Branch Target Identification flags # Pointer Authentication and Branch Target Identification flags
@ -517,30 +523,29 @@ else ifeq (${BRANCH_PROTECTION},4)
# Turn on branch target identification mechanism # Turn on branch target identification mechanism
BP_OPTION := bti BP_OPTION := bti
ENABLE_BTI := 1 ENABLE_BTI := 1
else ifeq (${BRANCH_PROTECTION},5)
# Turn on branch target identification mechanism
BP_OPTION := standard
ENABLE_BTI := 2
ENABLE_PAUTH := 2
else else
$(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION}) $(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
endif #(BRANCH_PROTECTION) endif #(BRANCH_PROTECTION)
ifeq ($(ENABLE_PAUTH),1) ifneq ($(ENABLE_PAUTH),0)
CTX_INCLUDE_PAUTH_REGS := 1 CTX_INCLUDE_PAUTH_REGS := ${ENABLE_PAUTH}
endif endif
ifneq (${BP_OPTION},none) ifneq (${BP_OPTION},none)
TF_CFLAGS_aarch64 += -mbranch-protection=${BP_OPTION} TF_CFLAGS_aarch64 += -mbranch-protection=${BP_OPTION}
endif #(BP_OPTION) endif #(BP_OPTION)
# Pointer Authentication sources # Pointer Authentication sources
ifeq (${ENABLE_PAUTH}, 1) ifneq (${ENABLE_PAUTH},0)
# arm/common/aarch64/arm_pauth.c contains a sample platform hook to complete the # arm/common/aarch64/arm_pauth.c contains a sample platform hook to complete the
# Pauth support. As it's not secure, it must be reimplemented for real platforms # Pauth support. As it's not secure, it must be reimplemented for real platforms
BL_COMMON_SOURCES += lib/extensions/pauth/pauth_helpers.S BL_COMMON_SOURCES += lib/extensions/pauth/pauth.c
endif endif
################################################################################
# Setup arch_features based on ARM_ARCH_MAJOR, ARM_ARCH_MINOR provided from
# platform.
################################################################################
include ${MAKE_HELPERS_DIRECTORY}arch_features.mk
#################################################### ####################################################
# Enable required options for Memory Stack Tagging. # Enable required options for Memory Stack Tagging.
#################################################### ####################################################
@ -917,13 +922,13 @@ endif
# If pointer authentication is used in the firmware, make sure that all the # If pointer authentication is used in the firmware, make sure that all the
# registers associated to it are also saved and restored. # registers associated to it are also saved and restored.
# Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1. # Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1.
ifeq ($(ENABLE_PAUTH),1) ifneq ($(ENABLE_PAUTH),0)
ifeq ($(CTX_INCLUDE_PAUTH_REGS),0) ifeq ($(CTX_INCLUDE_PAUTH_REGS),0)
$(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS=1) $(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS to be enabled)
endif endif
endif #(ENABLE_PAUTH) endif #(ENABLE_PAUTH)
ifeq ($(CTX_INCLUDE_PAUTH_REGS),1) ifneq ($(CTX_INCLUDE_PAUTH_REGS),0)
ifneq (${ARCH},aarch64) ifneq (${ARCH},aarch64)
$(error CTX_INCLUDE_PAUTH_REGS requires AArch64) $(error CTX_INCLUDE_PAUTH_REGS requires AArch64)
endif endif

View File

@ -120,12 +120,12 @@ void bl2_main(void)
disable_mmu_icache_secure(); disable_mmu_icache_secure();
#endif /* !__aarch64__ */ #endif /* !__aarch64__ */
#if ENABLE_PAUTH
/* /*
* Disable pointer authentication before running next boot image * Disable pointer authentication before running next boot image
*/ */
pauth_disable_el1(); if (is_feat_pauth_supported()) {
#endif /* ENABLE_PAUTH */ pauth_disable_el1();
}
#if ENABLE_RUNTIME_INSTRUMENTATION #if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(bl_svc, BL2_EXIT, PMF_CACHE_MAINT); PMF_CAPTURE_TIMESTAMP(bl_svc, BL2_EXIT, PMF_CACHE_MAINT);
@ -148,12 +148,12 @@ void bl2_main(void)
#endif #endif
console_flush(); console_flush();
#if ENABLE_PAUTH
/* /*
* Disable pointer authentication before running next boot image * Disable pointer authentication before running next boot image
*/ */
pauth_disable_el3(); if (is_feat_pauth_supported()) {
#endif /* ENABLE_PAUTH */ pauth_disable_el3();
}
bl2_run_next_image(next_bl_ep_info); bl2_run_next_image(next_bl_ep_info);
#endif /* BL2_RUNS_AT_EL3 */ #endif /* BL2_RUNS_AT_EL3 */

View File

@ -397,8 +397,26 @@ do_crash_reporting:
ldr x4, [x0, #REGSZ * 7] ldr x4, [x0, #REGSZ * 7]
#if ENABLE_PAUTH #if ENABLE_PAUTH
#if ENABLE_PAUTH == 2
/* Skip if not present in hardware */
is_feat_pauth_present_asm x0, x1
beq 1f
#endif
/*
* The assembler must see support for xpaci. So turn the compiler
* extension on. GCC prior to 10 doesn't understand the PAuth extension
* but it does understand armv8.3-a in general. Avoid using 8.3 if
* the compiler understands "pauth" so we don't downgrade a higher
* -march that was specified on the commandline.
*/
#if __GNUC__ < 10
.arch armv8.3-a
#else
.arch_extension pauth
#endif
/* Demangle address */ /* Demangle address */
xpaci x4 xpaci x4
1:
#endif #endif
bl asm_print_hex bl asm_print_hex
bl asm_print_newline bl asm_print_newline

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -8,6 +8,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <arch_features.h>
#include <arch_helpers.h> #include <arch_helpers.h>
#include <common/debug.h> #include <common/debug.h>
#include <drivers/console.h> #include <drivers/console.h>
@ -41,15 +42,14 @@ static inline uintptr_t extract_address(uintptr_t address)
{ {
uintptr_t ret = address; uintptr_t ret = address;
#if ENABLE_PAUTH
/* /*
* When pointer authentication is enabled, the LR value saved on the * When pointer authentication is enabled, the LR value saved on the
* stack contains a PAC. It must be stripped to retrieve the return * stack contains a PAC. It must be stripped to retrieve the return
* address. * address.
*/ */
if (is_feat_pauth_supported()) {
xpaci(ret); ret = xpaci(address);
#endif }
return ret; return ret;
} }

View File

@ -113,12 +113,16 @@ Common build options
- ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication - ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication
and ARMv8.5 Branch Target Identification support for TF-A BL images themselves. and ARMv8.5 Branch Target Identification support for TF-A BL images themselves.
If enabled, it is needed to use a compiler that supports the option If enabled, it is needed to use a compiler that supports the option
``-mbranch-protection``. Selects the branch protection features to use: ``-mbranch-protection``. The value of the ``-march`` (via ``ARM_ARCH_MINOR``
- 0: Default value turns off all types of branch protection and ``ARM_ARCH_MAJOR``) option will control which instructions will be
emitted (HINT space or not). Selects the branch protection features to use:
- 0: Default value turns off all types of branch protection (FEAT_STATE_DISABLED)
- 1: Enables all types of branch protection features - 1: Enables all types of branch protection features
- 2: Return address signing to its standard level - 2: Return address signing to its standard level
- 3: Extend the signing to include leaf functions - 3: Extend the signing to include leaf functions
- 4: Turn on branch target identification mechanism - 4: Turn on branch target identification mechanism
- 5: Enables all types of branch protection features, only if present in
hardware (FEAT_STATE_CHECK).
The table below summarizes ``BRANCH_PROTECTION`` values, GCC compilation options The table below summarizes ``BRANCH_PROTECTION`` values, GCC compilation options
and resulting PAuth/BTI features. and resulting PAuth/BTI features.
@ -136,6 +140,8 @@ Common build options
+-------+--------------+-------+-----+ +-------+--------------+-------+-----+
| 4 | bti | N | Y | | 4 | bti | N | Y |
+-------+--------------+-------+-----+ +-------+--------------+-------+-----+
| 5 | dynamic | Y | Y |
+-------+--------------+-------+-----+
This option defaults to 0. This option defaults to 0.
Note that Pointer Authentication is enabled for Non-secure world Note that Pointer Authentication is enabled for Non-secure world
@ -198,11 +204,13 @@ Common build options
- ``CTX_INCLUDE_PAUTH_REGS``: Numeric value to enable the Pointer - ``CTX_INCLUDE_PAUTH_REGS``: Numeric value to enable the Pointer
Authentication for Secure world. This will cause the ARMv8.3-PAuth registers Authentication for Secure world. This will cause the ARMv8.3-PAuth registers
to be included when saving and restoring the CPU context as part of world to be included when saving and restoring the CPU context as part of world
switch. This flag can take values 0 to 2, to align with ``ENABLE_FEAT`` switch. Automatically enabled when ``BRANCH_PROTECTION`` is enabled. This flag
mechanism. Default value is 0. can take values 0 to 2, to align with ``ENABLE_FEAT`` mechanism. Default value
is 0.
Note that Pointer Authentication is enabled for Non-secure world irrespective Note that Pointer Authentication is enabled for Non-secure world irrespective
of the value of this flag if the CPU supports it. of the value of this flag if the CPU supports it. Alternatively, when
``BRANCH_PROTECTION`` is enabled, this flag is superseded.
- ``CTX_INCLUDE_SVE_REGS``: Boolean option that, when set to 1, will cause the - ``CTX_INCLUDE_SVE_REGS``: Boolean option that, when set to 1, will cause the
SVE registers to be included when saving and restoring the CPU context. Note SVE registers to be included when saving and restoring the CPU context. Note

View File

@ -238,7 +238,15 @@ DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e3r)
/******************************************************************************* /*******************************************************************************
* Strip Pointer Authentication Code * Strip Pointer Authentication Code
******************************************************************************/ ******************************************************************************/
DEFINE_SYSOP_PARAM_FUNC(xpaci) static inline u_register_t xpaci(u_register_t arg)
{
register u_register_t x0 asm("x0") = arg;
/* `xpaci x0` for compatibility with older compiler and/or older -march */
__asm__ (".arch armv8.3-a; xpaci %0\n" : "+r" (x0));
return x0;
}
void flush_dcache_range(uintptr_t addr, size_t size); void flush_dcache_range(uintptr_t addr, size_t size);
void flush_dcache_to_popa_range(uintptr_t addr, size_t size); void flush_dcache_to_popa_range(uintptr_t addr, size_t size);

View File

@ -329,7 +329,7 @@
.endm .endm
/* /*
* is_feat_sysreg128_present_asm - Set flags and reg if FEAT_SYSREG128 * is_feat_XYZ_present_asm - Set flags and reg if FEAT_XYZ
* is enabled at runtime. * is enabled at runtime.
* *
* Arguments: * Arguments:
@ -342,6 +342,15 @@
ands \reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT) ands \reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
.endm .endm
.macro is_feat_pauth_present_asm reg:req, clobber:req
mrs \reg, ID_AA64ISAR1_EL1
mov_imm \clobber, ((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))
tst \reg, \clobber
.endm
.macro call_reset_handler .macro call_reset_handler
#if !(defined(IMAGE_BL2) && ENABLE_RME) #if !(defined(IMAGE_BL2) && ENABLE_RME)
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------

View File

@ -379,6 +379,11 @@ no_mpam:
mrs x9, pmcr_el0 mrs x9, pmcr_el0
str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0] str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0]
#if CTX_INCLUDE_PAUTH_REGS #if CTX_INCLUDE_PAUTH_REGS
#if CTX_INCLUDE_PAUTH_REGS == 2
/* Skip if not present in hardware */
is_feat_pauth_present_asm x9, x10
beq no_pauth_\@
#endif
/* ---------------------------------------------------------- /* ----------------------------------------------------------
* Save the ARMv8.3-PAuth keys as they are not banked * Save the ARMv8.3-PAuth keys as they are not banked
* by exception level * by exception level
@ -419,6 +424,7 @@ no_mpam:
/* Program instruction key A */ /* Program instruction key A */
msr APIAKeyLo_EL1, x10 msr APIAKeyLo_EL1, x10
msr APIAKeyHi_EL1, x11 msr APIAKeyHi_EL1, x11
no_pauth_\@:
#endif /* ENABLE_PAUTH */ #endif /* ENABLE_PAUTH */
#endif /* CTX_INCLUDE_PAUTH_REGS */ #endif /* CTX_INCLUDE_PAUTH_REGS */
.endm /* save_gp_pmcr_pauth_regs */ .endm /* save_gp_pmcr_pauth_regs */
@ -460,6 +466,11 @@ endfunc prepare_el3_entry
*/ */
func restore_gp_pmcr_pauth_regs func restore_gp_pmcr_pauth_regs
#if CTX_INCLUDE_PAUTH_REGS #if CTX_INCLUDE_PAUTH_REGS
#if CTX_INCLUDE_PAUTH_REGS == 2
/* Skip if not present in hardware */
is_feat_pauth_present_asm x0, x1
beq no_pauth
#endif
/* Restore the ARMv8.3 PAuth keys */ /* Restore the ARMv8.3 PAuth keys */
add x10, sp, #CTX_PAUTH_REGS_OFFSET add x10, sp, #CTX_PAUTH_REGS_OFFSET
@ -479,6 +490,7 @@ func restore_gp_pmcr_pauth_regs
msr APDBKeyHi_EL1, x7 msr APDBKeyHi_EL1, x7
msr APGAKeyLo_EL1, x8 msr APGAKeyLo_EL1, x8
msr APGAKeyHi_EL1, x9 msr APGAKeyHi_EL1, x9
no_pauth:
#endif /* CTX_INCLUDE_PAUTH_REGS */ #endif /* CTX_INCLUDE_PAUTH_REGS */
/* PMUv3 is presumed to be always present */ /* PMUv3 is presumed to be always present */

View File

@ -1,11 +1,12 @@
/* /*
* Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved. * Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include <string.h> #include <string.h>
#include <arch_features.h>
#include <common/debug.h> #include <common/debug.h>
#include <context.h> #include <context.h>
#include <lib/el3_runtime/context_mgmt.h> #include <lib/el3_runtime/context_mgmt.h>
@ -65,11 +66,11 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
#else #else
size_t el1_total = 0U; size_t el1_total = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */ #endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_total = 0U; size_t pauth_total = 0U;
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
}
PRINT_MEM_USAGE_SEPARATOR(); PRINT_MEM_USAGE_SEPARATOR();
@ -80,9 +81,9 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| EL1 "); printf("| EL1 ");
#endif /* CTX_INCLUDE_EL2_REGS */ #endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
printf("| PAUTH "); printf("| PAUTH ");
#endif }
printf("| Other | Total |\n"); printf("| Other | Total |\n");
@ -96,11 +97,11 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
#else #else
size_t el1_size = 0U; size_t el1_size = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */ #endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_size = 0U; size_t pauth_size = 0U;
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
}
PRINT_MEM_USAGE_SEPARATOR(); PRINT_MEM_USAGE_SEPARATOR();
@ -124,12 +125,12 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| %8luB ", el1_size); printf("| %8luB ", el1_size);
#endif /* CTX_INCLUDE_EL2_REGS */ #endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
pauth_size = sizeof(ctx->pauth_ctx); pauth_size = sizeof(ctx->pauth_ctx);
size_other -= pauth_size; size_other -= pauth_size;
pauth_total += pauth_size; pauth_total += pauth_size;
printf("| %8luB ", pauth_size); printf("| %8luB ", pauth_size);
#endif }
printf("| %8luB | %8luB |\n", size_other, core_total); printf("| %8luB | %8luB |\n", size_other, core_total);
gp_total += gp_size; gp_total += gp_size;
@ -138,15 +139,15 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
total += core_total; total += core_total;
} }
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK(); PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif }
PRINT_MEM_USAGE_SEPARATOR(); PRINT_MEM_USAGE_SEPARATOR();
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK(); PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif }
PRINT_MEM_USAGE_SEPARATOR(); PRINT_MEM_USAGE_SEPARATOR();
@ -158,15 +159,15 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| %8luB ", el1_total); printf("| %8luB ", el1_total);
#endif /* CTX_INCLUDE_EL2_REGS */ #endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
printf("| %8luB ", pauth_total); printf("| %8luB ", pauth_total);
#endif }
printf("| %8luB | %8luB |\n", other_total, total); printf("| %8luB | %8luB |\n", other_total, total);
#if CTX_INCLUDE_PAUTH_REGS if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK(); PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif }
PRINT_MEM_USAGE_SEPARATOR(); PRINT_MEM_USAGE_SEPARATOR();
printf("\n"); printf("\n");

View File

@ -356,7 +356,7 @@ BL31_SOURCES += lib/extensions/ras/std_err_record.c \
endif endif
# Pointer Authentication sources # Pointer Authentication sources
ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3)) ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3 5))
PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c
endif endif

View File

@ -148,7 +148,7 @@ $(error "This is an AArch64-only port; CTX_INCLUDE_AARCH32_REGS must be disabled
endif endif
# Pointer Authentication sources # Pointer Authentication sources
ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3)) ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3 5))
PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c
endif endif