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}
################################################################################
# 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
# Pointer Authentication and Branch Target Identification flags
@ -517,30 +523,29 @@ else ifeq (${BRANCH_PROTECTION},4)
# Turn on branch target identification mechanism
BP_OPTION := bti
ENABLE_BTI := 1
else ifeq (${BRANCH_PROTECTION},5)
# Turn on branch target identification mechanism
BP_OPTION := standard
ENABLE_BTI := 2
ENABLE_PAUTH := 2
else
$(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
endif #(BRANCH_PROTECTION)
ifeq ($(ENABLE_PAUTH),1)
CTX_INCLUDE_PAUTH_REGS := 1
ifneq ($(ENABLE_PAUTH),0)
CTX_INCLUDE_PAUTH_REGS := ${ENABLE_PAUTH}
endif
ifneq (${BP_OPTION},none)
TF_CFLAGS_aarch64 += -mbranch-protection=${BP_OPTION}
endif #(BP_OPTION)
# 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
# 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
################################################################################
# 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.
####################################################
@ -917,13 +922,13 @@ 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 keys used by EL3 to EL1 and S-EL1.
ifeq ($(ENABLE_PAUTH),1)
ifneq ($(ENABLE_PAUTH),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 #(ENABLE_PAUTH)
ifeq ($(CTX_INCLUDE_PAUTH_REGS),1)
ifneq ($(CTX_INCLUDE_PAUTH_REGS),0)
ifneq (${ARCH},aarch64)
$(error CTX_INCLUDE_PAUTH_REGS requires AArch64)
endif

View File

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

View File

@ -397,8 +397,26 @@ do_crash_reporting:
ldr x4, [x0, #REGSZ * 7]
#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 */
xpaci x4
1:
#endif
bl asm_print_hex
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
*/
@ -8,6 +8,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/console.h>
@ -41,15 +42,14 @@ static inline uintptr_t extract_address(uintptr_t address)
{
uintptr_t ret = address;
#if ENABLE_PAUTH
/*
* When pointer authentication is enabled, the LR value saved on the
* stack contains a PAC. It must be stripped to retrieve the return
* address.
*/
xpaci(ret);
#endif
if (is_feat_pauth_supported()) {
ret = xpaci(address);
}
return ret;
}

View File

@ -113,12 +113,16 @@ Common build options
- ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication
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
``-mbranch-protection``. Selects the branch protection features to use:
- 0: Default value turns off all types of branch protection
``-mbranch-protection``. The value of the ``-march`` (via ``ARM_ARCH_MINOR``
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
- 2: Return address signing to its standard level
- 3: Extend the signing to include leaf functions
- 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
and resulting PAuth/BTI features.
@ -136,6 +140,8 @@ Common build options
+-------+--------------+-------+-----+
| 4 | bti | N | Y |
+-------+--------------+-------+-----+
| 5 | dynamic | Y | Y |
+-------+--------------+-------+-----+
This option defaults to 0.
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
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
switch. This flag can take values 0 to 2, to align with ``ENABLE_FEAT``
mechanism. Default value is 0.
switch. Automatically enabled when ``BRANCH_PROTECTION`` is enabled. This flag
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
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
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
******************************************************************************/
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_to_popa_range(uintptr_t addr, size_t size);

View File

@ -329,7 +329,7 @@
.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.
*
* Arguments:
@ -342,6 +342,15 @@
ands \reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
.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
#if !(defined(IMAGE_BL2) && ENABLE_RME)
/* ---------------------------------------------------------------------

View File

@ -379,6 +379,11 @@ no_mpam:
mrs x9, pmcr_el0
str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0]
#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
* by exception level
@ -419,6 +424,7 @@ no_mpam:
/* Program instruction key A */
msr APIAKeyLo_EL1, x10
msr APIAKeyHi_EL1, x11
no_pauth_\@:
#endif /* ENABLE_PAUTH */
#endif /* CTX_INCLUDE_PAUTH_REGS */
.endm /* save_gp_pmcr_pauth_regs */
@ -460,6 +466,11 @@ endfunc prepare_el3_entry
*/
func restore_gp_pmcr_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 */
add x10, sp, #CTX_PAUTH_REGS_OFFSET
@ -479,6 +490,7 @@ func restore_gp_pmcr_pauth_regs
msr APDBKeyHi_EL1, x7
msr APGAKeyLo_EL1, x8
msr APGAKeyHi_EL1, x9
no_pauth:
#endif /* CTX_INCLUDE_PAUTH_REGS */
/* 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
*/
#include <string.h>
#include <arch_features.h>
#include <common/debug.h>
#include <context.h>
#include <lib/el3_runtime/context_mgmt.h>
@ -65,11 +66,11 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
#else
size_t el1_total = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_total = 0U;
if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif
}
PRINT_MEM_USAGE_SEPARATOR();
@ -80,9 +81,9 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| EL1 ");
#endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
printf("| PAUTH ");
#endif
}
printf("| Other | Total |\n");
@ -96,11 +97,11 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
#else
size_t el1_size = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_size = 0U;
if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif
}
PRINT_MEM_USAGE_SEPARATOR();
@ -124,12 +125,12 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| %8luB ", el1_size);
#endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
pauth_size = sizeof(ctx->pauth_ctx);
size_other -= pauth_size;
pauth_total += pauth_size;
printf("| %8luB ", pauth_size);
#endif
}
printf("| %8luB | %8luB |\n", size_other, core_total);
gp_total += gp_size;
@ -138,15 +139,15 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
total += core_total;
}
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif
}
PRINT_MEM_USAGE_SEPARATOR();
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif
}
PRINT_MEM_USAGE_SEPARATOR();
@ -158,15 +159,15 @@ static size_t report_allocated_memory(unsigned int security_state_idx)
printf("| %8luB ", el1_total);
#endif /* CTX_INCLUDE_EL2_REGS */
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
printf("| %8luB ", pauth_total);
#endif
}
printf("| %8luB | %8luB |\n", other_total, total);
#if CTX_INCLUDE_PAUTH_REGS
if (is_ctx_pauth_supported()) {
PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
#endif
}
PRINT_MEM_USAGE_SEPARATOR();
printf("\n");

View File

@ -356,7 +356,7 @@ BL31_SOURCES += lib/extensions/ras/std_err_record.c \
endif
# 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
endif

View File

@ -148,7 +148,7 @@ $(error "This is an AArch64-only port; CTX_INCLUDE_AARCH32_REGS must be disabled
endif
# 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
endif