From 09cc777daafed62af0e6139a2dbc9858d1ec3622 Mon Sep 17 00:00:00 2001 From: Sudan Landge Date: Wed, 23 Jul 2025 11:29:14 +0100 Subject: [PATCH] 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 --- arch/arm/core/cortex_m/swap_helper.S | 13 +++++++++++++ arch/arm/core/cortex_m/thread.c | 12 +++++++++++- arch/arm/core/offsets/offsets_aarch32.c | 5 +++++ arch/arm/include/offsets_short_arch.h | 5 +++++ arch/common/Kconfig | 17 +++++++++++++++++ doc/hardware/arch/arm_cortex_m.rst | 5 +++++ include/zephyr/arch/arm/thread.h | 14 ++++++++++++++ modules/cmsis_6/cmsis_core_m_defaults.h | 6 ++++++ 8 files changed, 76 insertions(+), 1 deletion(-) diff --git a/arch/arm/core/cortex_m/swap_helper.S b/arch/arm/core/cortex_m/swap_helper.S index 40f00fc0056..b7a87a4d633 100644 --- a/arch/arm/core/cortex_m/swap_helper.S +++ b/arch/arm/core/cortex_m/swap_helper.S @@ -2,6 +2,7 @@ * Copyright (c) 2013-2014 Wind River Systems, Inc. * Copyright (c) 2017-2019 Nordic Semiconductor ASA. * Copyright (c) 2020 Stephanos Ioannidis + * Copyright 2025 Arm Limited and/or its affiliates * * 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} diff --git a/arch/arm/core/cortex_m/thread.c b/arch/arm/core/cortex_m/thread.c index a1e281af4d5..444eac76bc0 100644 --- a/arch/arm/core/cortex_m/thread.c +++ b/arch/arm/core/cortex_m/thread.c @@ -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 * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ #include #include #include +#include #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. diff --git a/arch/arm/core/offsets/offsets_aarch32.c b/arch/arm/core/offsets/offsets_aarch32.c index 693546630b0..e8236d8459f 100644 --- a/arch/arm/core/offsets/offsets_aarch32.c +++ b/arch/arm/core/offsets/offsets_aarch32.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright 2025 Arm Limited and/or its affiliates * * 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); diff --git a/arch/arm/include/offsets_short_arch.h b/arch/arm/include/offsets_short_arch.h index ea6af4db92d..d9c3c5e4d03 100644 --- a/arch/arm/include/offsets_short_arch.h +++ b/arch/arm/include/offsets_short_arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Carlo Caione + * Copyright 2025 Arm Limited and/or its affiliates * * 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 */ diff --git a/arch/common/Kconfig b/arch/common/Kconfig index 19832da45ae..59b0532b12e 100644 --- a/arch/common/Kconfig +++ b/arch/common/Kconfig @@ -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 diff --git a/doc/hardware/arch/arm_cortex_m.rst b/doc/hardware/arch/arm_cortex_m.rst index 772673b78ee..139f00429d8 100644 --- a/doc/hardware/arch/arm_cortex_m.rst +++ b/doc/hardware/arch/arm_cortex_m.rst @@ -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., diff --git a/include/zephyr/arch/arm/thread.h b/include/zephyr/arch/arm/thread.h index 139f606809f..d65f1bf0eff 100644 --- a/include/zephyr/arch/arm/thread.h +++ b/include/zephyr/arch/arm/thread.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright 2025 Arm Limited and/or its affiliates * * 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) diff --git a/modules/cmsis_6/cmsis_core_m_defaults.h b/modules/cmsis_6/cmsis_core_m_defaults.h index b210d5c0d68..919b078fc3c 100644 --- a/modules/cmsis_6/cmsis_core_m_defaults.h +++ b/modules/cmsis_6/cmsis_core_m_defaults.h @@ -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 +#endif + #endif /* ZEPHYR_MODULES_CMSIS_6_CMSIS_CORE_M_DEFAULTS_H_ */