Skip to content

Commit 1916ec2

Browse files
wearyzenhenrikbrixandersen
authored andcommitted
arch: arm: support PACBTI with unprivileged mode
To support unprivileged mode (CONFIG_USERSPACE): - Set unprivileged PAC key registers when system is in unprivileged mode. - Add `bti` after each svc call, to make sure that the indirect jumps on `lr` while returning from an `svc` don't result in a usage fault. Signed-off-by: Sudan Landge <[email protected]>
1 parent 09cc777 commit 1916ec2

File tree

6 files changed

+45
-13
lines changed

6 files changed

+45
-13
lines changed

arch/arm/core/cortex_m/swap_helper.S

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ SECTION_FUNC(TEXT, z_arm_pendsv)
316316

317317
#ifdef CONFIG_ARM_PAC_PER_THREAD
318318
/* Read thread's dedicated PAC key and write them in the privileged PAC key registers.
319+
* Note: There is no way to know the _current thread mode after the thread creation since
320+
* `_current->arch.mode` for the userspace thread is set in z_arm_userspace_enter() which
321+
* runs after z_arm_pendsv is done. So for now, while switching to an unprivileged thread
322+
* the same PAC keys are set in both privileged and unprivileged PAC key registers.
323+
* TODO: find a way to not set privileged PAC keys if the thread being switched into is an
324+
* unprivileged thread.
319325
*/
320326
add r0, r2, #_thread_offset_to_pac_keys
321327
ldmia r0!, {r3-r6}

arch/arm/core/irq_offload.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2015 Intel corporation
3+
* Copyright 2025 Arm Limited and/or its affiliates <[email protected]>
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -34,7 +35,8 @@ void arch_irq_offload(irq_offload_routine_t routine, const void *parameter)
3435
offload_routine = routine;
3536
offload_param = parameter;
3637

37-
__asm__ volatile ("svc %[id]"
38+
__asm__ volatile ("svc %[id]\n"
39+
IF_ENABLED(CONFIG_ARM_BTI, ("bti"))
3840
:
3941
: [id] "i" (_SVC_CALL_IRQ_OFFLOAD)
4042
: "memory");

arch/arm/core/userspace.S

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,24 @@ SECTION_FUNC(TEXT,z_arm_userspace_enter)
273273
orrs ip, ip, #1
274274
/* Store (unprivileged) mode in thread's mode state variable */
275275
str r1, [r0, #_thread_offset_to_mode]
276+
277+
#ifdef CONFIG_ARM_PAC_PER_THREAD
278+
/* Read thread's dedicated PAC key and since we are in unprivileged mode write them in the
279+
* unprivileged PAC key registers.
280+
* This needs to be done before we switch to unprivileged mode.
281+
*/
282+
add r1, r0, #_thread_offset_to_pac_keys
283+
ldmia r1!, {r3-r6}
284+
msr PAC_KEY_U_0, r3
285+
msr PAC_KEY_U_1, r4
286+
msr PAC_KEY_U_2, r5
287+
msr PAC_KEY_U_3, r6
288+
clrm {r3-r6}
289+
#endif
276290
#endif
277291
dsb
278292
msr CONTROL, ip
279-
#endif
293+
#endif /* CONFIG_CPU_AARCH32_CORTEX_R */
280294

281295
/* ISB is not strictly necessary here (stack pointer is not being
282296
* touched), but it's recommended to avoid executing pre-fetched

arch/common/Kconfig

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ config ARM_PAC_PER_THREAD
8080
bool "Set cryptographically secure PAC key per thread"
8181
depends on ARM_PAC
8282
depends on ENTROPY_DEVICE_RANDOM_GENERATOR || TIMER_RANDOM_GENERATOR
83-
depends on !USERSPACE
8483
help
8584
Select this option to generate and use unique keys per thread to generate Pointer
8685
Authentication Code.
@@ -115,48 +114,48 @@ choice ARM_PACBTI
115114

116115
config ARM_PACBTI_STANDARD
117116
bool "Standard (PACRET + LEAF + BTI)"
118-
select ARM_PAC if !USERSPACE
119-
select ARM_BTI if !USERSPACE
117+
select ARM_PAC
118+
select ARM_BTI
120119
help
121120
This option instructs the compiler to generate code with all branch protection features
122121
enabled at their standard level.
123122

124123
config ARM_PACBTI_PACRET
125124
bool "PACRET only"
126-
select ARM_PAC if !USERSPACE
125+
select ARM_PAC
127126
help
128127
This option instructs the compiler to generate code with return address signing for
129128
all functions that save the return address to memory.
130129

131130
config ARM_PACBTI_PACRET_LEAF
132131
bool "PACRET + Leaf"
133-
select ARM_PAC if !USERSPACE
132+
select ARM_PAC
134133
help
135134
This option instructs the compiler to generate code with return address signing for
136135
all functions that save the return address to memory and,
137136
also sign leaf functions even if they do not write the return address to memory.
138137

139138
config ARM_PACBTI_BTI
140139
bool "BTI only"
141-
select ARM_BTI if !USERSPACE
140+
select ARM_BTI
142141
help
143142
This option enables Branch Target Identification (BTI), which inserts special landing
144143
pad instructions at valid indirect branch targets. This option does not enable Pointer
145144
Authentication (PAC).
146145

147146
config ARM_PACBTI_PACRET_BTI
148147
bool "PACRET + BTI"
149-
select ARM_PAC if !USERSPACE
150-
select ARM_BTI if !USERSPACE
148+
select ARM_PAC
149+
select ARM_BTI
151150
help
152151
This option instructs the compiler to generate code with return address signing for
153152
all functions that save the return address to memory and,
154153
add landing-pad instructions at the permitted targets of indirect branch instructions
155154

156155
config ARM_PACBTI_PACRET_LEAF_BTI
157156
bool "PACRET + Leaf + BTI"
158-
select ARM_PAC if !USERSPACE
159-
select ARM_BTI if !USERSPACE
157+
select ARM_PAC
158+
select ARM_BTI
160159
help
161160
This option instructs the compiler to generate code with return address signing for
162161
all functions that save the return address to memory and,

include/zephyr/arch/arm/error.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) 2013-2014 Wind River Systems, Inc.
3-
* Copyright (c) 2023 Arm Limited
3+
* Copyright 2023, 2025 Arm Limited and/or its affiliates <[email protected]>
44
*
55
* SPDX-License-Identifier: Apache-2.0
66
*/
@@ -39,6 +39,7 @@ do {\
3939
__asm__ volatile( \
4040
"mov r0, %[_reason]\n" \
4141
"svc %[id]\n" \
42+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n")) \
4243
:: [_reason] "r" (reason_p), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \
4344
: "r0", "memory"); \
4445
} while (false)
@@ -59,6 +60,7 @@ do { \
5960
"push {lr}\n\t" \
6061
"cpsie i\n\t" \
6162
"svc %[id]\n\t" \
63+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n\t")) \
6264
"pop {lr}\n\t" \
6365
: \
6466
: "r" (r0), [id] "i" (_SVC_CALL_RUNTIME_EXCEPT) \

include/zephyr/arch/arm/syscall.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2018 Linaro Limited.
3+
* Copyright 2025 Arm Limited and/or its affiliates <[email protected]>
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -27,6 +28,7 @@
2728
#include <zephyr/types.h>
2829
#include <stdbool.h>
2930
#include <zephyr/arch/arm/misc.h>
31+
#include <zephyr/sys/util_macro.h>
3032

3133
#ifdef __cplusplus
3234
extern "C" {
@@ -50,6 +52,7 @@ static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2,
5052
register uint32_t r6 __asm__("r6") = call_id;
5153

5254
__asm__ volatile("svc %[svid]\n"
55+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
5356
: "=r"(ret), "=r"(r1), "=r"(r2), "=r"(r3)
5457
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
5558
"r" (ret), "r" (r1), "r" (r2), "r" (r3),
@@ -72,6 +75,7 @@ static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2,
7275
register uint32_t r6 __asm__("r6") = call_id;
7376

7477
__asm__ volatile("svc %[svid]\n"
78+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
7579
: "=r"(ret), "=r"(r1), "=r"(r2), "=r"(r3)
7680
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
7781
"r" (ret), "r" (r1), "r" (r2), "r" (r3),
@@ -92,6 +96,7 @@ static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2,
9296
register uint32_t r6 __asm__("r6") = call_id;
9397

9498
__asm__ volatile("svc %[svid]\n"
99+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
95100
: "=r"(ret), "=r"(r1), "=r"(r2), "=r"(r3)
96101
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
97102
"r" (ret), "r" (r1), "r" (r2), "r" (r3),
@@ -111,6 +116,7 @@ static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2,
111116
register uint32_t r6 __asm__("r6") = call_id;
112117

113118
__asm__ volatile("svc %[svid]\n"
119+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
114120
: "=r"(ret), "=r"(r1), "=r"(r2)
115121
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
116122
"r" (ret), "r" (r1), "r" (r2), "r" (r6)
@@ -127,6 +133,7 @@ static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2,
127133
register uint32_t r6 __asm__("r6") = call_id;
128134

129135
__asm__ volatile("svc %[svid]\n"
136+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
130137
: "=r"(ret), "=r"(r1)
131138
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
132139
"r" (ret), "r" (r1), "r" (r6)
@@ -142,6 +149,7 @@ static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1,
142149
register uint32_t r6 __asm__("r6") = call_id;
143150

144151
__asm__ volatile("svc %[svid]\n"
152+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
145153
: "=r"(ret)
146154
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
147155
"r" (ret), "r" (r6)
@@ -155,6 +163,7 @@ static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id)
155163
register uint32_t r6 __asm__("r6") = call_id;
156164

157165
__asm__ volatile("svc %[svid]\n"
166+
IF_ENABLED(CONFIG_ARM_BTI, ("bti\n"))
158167
: "=r"(ret)
159168
: [svid] "i" (_SVC_CALL_SYSTEM_CALL),
160169
"r" (ret), "r" (r6)

0 commit comments

Comments
 (0)