arch: arm: add per thread unique PAC key support

Add a config option to set unique PAC keys per thread and
make sure to retain them during context switch.

Signed-off-by: Sudan Landge <sudan.landge@arm.com>
This commit is contained in:
Sudan Landge
2025-07-23 11:29:14 +01:00
committed by Henrik Brix Andersen
parent 8e5f828fef
commit 09cc777daa
8 changed files with 76 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2013-2014 Wind River Systems, Inc.
* Copyright (c) 2017-2019 Nordic Semiconductor ASA.
* Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -313,6 +314,18 @@ SECTION_FUNC(TEXT, z_arm_pendsv)
#endif
#ifdef CONFIG_ARM_PAC_PER_THREAD
/* Read thread's dedicated PAC key and write them in the privileged PAC key registers.
*/
add r0, r2, #_thread_offset_to_pac_keys
ldmia r0!, {r3-r6}
msr PAC_KEY_P_0, r3
msr PAC_KEY_P_1, r4
msr PAC_KEY_P_2, r5
msr PAC_KEY_P_3, r6
clrm {r3-r6}
#endif /* CONFIG_ARM_PAC_PER_THREAD */
/* load callee-saved + psp from thread */
add r0, r2, #_thread_offset_to_callee_saved
ldmia r0, {r4-r11, ip}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2013-2014 Wind River Systems, Inc.
* Copyright (c) 2021 Lexmark International, Inc.
* Copyright (c) 2023 Arm Limited
* Copyright (c) 2023, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -20,6 +20,7 @@
#include <zephyr/sys/barrier.h>
#include <stdbool.h>
#include <cmsis_core.h>
#include <zephyr/random/random.h>
#if (MPU_GUARD_ALIGN_AND_SIZE_FLOAT > MPU_GUARD_ALIGN_AND_SIZE)
#define FP_GUARD_EXTRA_SIZE (MPU_GUARD_ALIGN_AND_SIZE_FLOAT - MPU_GUARD_ALIGN_AND_SIZE)
@@ -121,6 +122,12 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, char *sta
#if defined(CONFIG_USERSPACE)
thread->arch.priv_stack_start = 0;
#endif
#endif
#ifdef CONFIG_ARM_PAC_PER_THREAD
/* Generate PAC key and save it in thread context to be set later
* when the thread is actually switched in
*/
sys_csrand_get(&thread->arch.pac_keys, sizeof(struct pac_keys));
#endif
/*
* initial values in all other registers/thread entries are
@@ -541,6 +548,9 @@ void arch_switch_to_main_thread(struct k_thread *main_thread, char *stack_ptr,
#endif
#endif /* CONFIG_BUILTIN_STACK_GUARD */
#ifdef CONFIG_ARM_PAC_PER_THREAD
__set_PAC_KEY_P((uint32_t *)&main_thread->arch.pac_keys);
#endif
/*
* Set PSP to the highest address of the main stack
* before enabling interrupts and jumping to main.

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-2014 Wind River Systems, Inc.
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -32,6 +33,10 @@
GEN_OFFSET_SYM(_thread_arch_t, basepri);
GEN_OFFSET_SYM(_thread_arch_t, swap_return_value);
#if defined(CONFIG_ARM_PAC_PER_THREAD)
GEN_OFFSET_SYM(_thread_arch_t, pac_keys);
#endif
#if defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R)
GEN_OFFSET_SYM(_thread_arch_t, exception_depth);
GEN_OFFSET_SYM(_cpu_arch_t, exc_depth);

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com>
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -59,6 +60,10 @@
(___thread_stack_info_t_start_OFFSET + ___thread_t_stack_info_OFFSET)
#endif
#if defined(CONFIG_ARM_PAC_PER_THREAD)
#define _thread_offset_to_pac_keys \
(___thread_t_arch_OFFSET + ___thread_arch_t_pac_keys_OFFSET)
#endif
/* end - threads */

View File

@@ -76,6 +76,23 @@ config ARM_MPU
of full partitioning the default behavior for the ARMv8-M and ARMv8-R MPU
driver.
config ARM_PAC_PER_THREAD
bool "Set cryptographically secure PAC key per thread"
depends on ARM_PAC
depends on ENTROPY_DEVICE_RANDOM_GENERATOR || TIMER_RANDOM_GENERATOR
depends on !USERSPACE
help
Select this option to generate and use unique keys per thread to generate Pointer
Authentication Code.
Internally, sys_csrand_get() is used as part of arch_new_thread() to generate
cryptographically secure random keys, which are saved in the thread's
architecture-specific context. These keys are then loaded into the PAC key registers
before switching to the thread during context switches.
Applications can chose to have hardware based random keys generator by selecting the right
generator from RNG_GENERATOR_CHOICE or by selecting TIMER_RANDOM_GENERATOR for testing
with pseudo random keys.
Note: GCC version 14.3 or higher is needed to support this option.
config ARM_PAC
bool
help

View File

@@ -459,6 +459,11 @@ automatically selected based on the branch protection option chosen for
:kconfig:option:`CONFIG_ARM_PACBTI`. These configuration options enforce PACBTI by enabling
corresponding PACBTI bits in CONTROL register and in the FVP.
To further enhance pointer authentication, Zephyr supports using cryptographically secure,
per-thread PAC keys by enabling :kconfig:option:`CONFIG_ARM_PAC_PER_THREAD`.
For more details on key generation sources and configuration, refer to the Kconfig help for
:kconfig:option:`CONFIG_ARM_PAC_PER_THREAD`.
**Limitations:**
- Only builds targeting Armv8.1-M Mainline processors with PACBTI hardware support (e.g.,

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Intel Corporation
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -60,6 +61,15 @@ struct _preempt_float {
};
#endif
#if defined(CONFIG_ARM_PAC_PER_THREAD)
struct pac_keys {
uint32_t key_0;
uint32_t key_1;
uint32_t key_2;
uint32_t key_3;
};
#endif
struct _thread_arch {
/* interrupt locking key */
@@ -134,6 +144,10 @@ struct _thread_arch {
#endif
#endif
#endif
#if defined(CONFIG_ARM_PAC_PER_THREAD)
struct pac_keys pac_keys;
#endif
};
#if defined(CONFIG_FPU_SHARING) && defined(CONFIG_MPU_STACK_GUARD)

View File

@@ -147,4 +147,10 @@ typedef enum {
#error "Unknown Cortex-M device"
#endif
#ifdef CONFIG_ARM_PAC
/* This provides apis to set/get PAC keys */
#define __ARM_FEATURE_PAUTH 1
#include <m-profile/armv81m_pac.h>
#endif
#endif /* ZEPHYR_MODULES_CMSIS_6_CMSIS_CORE_M_DEFAULTS_H_ */