122e6c808SNishad Kamdar /* SPDX-License-Identifier: GPL-2.0 */
275031975SMark Rutland #ifndef __ASM_POINTER_AUTH_H
375031975SMark Rutland #define __ASM_POINTER_AUTH_H
475031975SMark Rutland 
5ec6e822dSMark Rutland #include <linux/bitops.h>
620169862SPeter Collingbourne #include <linux/prctl.h>
775031975SMark Rutland #include <linux/random.h>
875031975SMark Rutland 
975031975SMark Rutland #include <asm/cpufeature.h>
10ec6e822dSMark Rutland #include <asm/memory.h>
1175031975SMark Rutland #include <asm/sysreg.h>
1275031975SMark Rutland 
13*de1702f6SMark Rutland /*
14*de1702f6SMark Rutland  * The EL0/EL1 pointer bits used by a pointer authentication code.
15*de1702f6SMark Rutland  * This is dependent on TBI0/TBI1 being enabled, or bits 63:56 would also apply.
16*de1702f6SMark Rutland  */
17*de1702f6SMark Rutland #define ptrauth_user_pac_mask()		GENMASK_ULL(54, vabits_actual)
18*de1702f6SMark Rutland #define ptrauth_kernel_pac_mask()	GENMASK_ULL(63, vabits_actual)
19*de1702f6SMark Rutland 
20d2e0d8f9SPeter Collingbourne #define PR_PAC_ENABLED_KEYS_MASK                                               \
21d2e0d8f9SPeter Collingbourne 	(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)
22d2e0d8f9SPeter Collingbourne 
2375031975SMark Rutland #ifdef CONFIG_ARM64_PTR_AUTH
2475031975SMark Rutland /*
2575031975SMark Rutland  * Each key is a 128-bit quantity which is split across a pair of 64-bit
2675031975SMark Rutland  * registers (Lo and Hi).
2775031975SMark Rutland  */
2875031975SMark Rutland struct ptrauth_key {
2975031975SMark Rutland 	unsigned long lo, hi;
3075031975SMark Rutland };
3175031975SMark Rutland 
3275031975SMark Rutland /*
3375031975SMark Rutland  * We give each process its own keys, which are shared by all threads. The keys
3475031975SMark Rutland  * are inherited upon fork(), and reinitialised upon exec*().
3575031975SMark Rutland  */
3691a1b6ccSKristina Martsenko struct ptrauth_keys_user {
3775031975SMark Rutland 	struct ptrauth_key apia;
3875031975SMark Rutland 	struct ptrauth_key apib;
3975031975SMark Rutland 	struct ptrauth_key apda;
4075031975SMark Rutland 	struct ptrauth_key apdb;
4175031975SMark Rutland 	struct ptrauth_key apga;
4275031975SMark Rutland };
4375031975SMark Rutland 
44b90e4839SPeter Collingbourne #define __ptrauth_key_install_nosync(k, v)			\
45b90e4839SPeter Collingbourne do {								\
46b90e4839SPeter Collingbourne 	struct ptrauth_key __pki_v = (v);			\
47b90e4839SPeter Collingbourne 	write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1);	\
48b90e4839SPeter Collingbourne 	write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);	\
49b90e4839SPeter Collingbourne } while (0)
50b90e4839SPeter Collingbourne 
51d053e71aSDaniel Kiss #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
52d053e71aSDaniel Kiss 
53d053e71aSDaniel Kiss struct ptrauth_keys_kernel {
54d053e71aSDaniel Kiss 	struct ptrauth_key apia;
55d053e71aSDaniel Kiss };
56d053e71aSDaniel Kiss 
ptrauth_keys_init_kernel(struct ptrauth_keys_kernel * keys)57d053e71aSDaniel Kiss static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
58d053e71aSDaniel Kiss {
59d053e71aSDaniel Kiss 	if (system_supports_address_auth())
60d053e71aSDaniel Kiss 		get_random_bytes(&keys->apia, sizeof(keys->apia));
61d053e71aSDaniel Kiss }
62d053e71aSDaniel Kiss 
ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel * keys)63d053e71aSDaniel Kiss static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
64d053e71aSDaniel Kiss {
65d053e71aSDaniel Kiss 	if (!system_supports_address_auth())
66d053e71aSDaniel Kiss 		return;
67d053e71aSDaniel Kiss 
68d053e71aSDaniel Kiss 	__ptrauth_key_install_nosync(APIA, keys->apia);
69d053e71aSDaniel Kiss 	isb();
70d053e71aSDaniel Kiss }
71d053e71aSDaniel Kiss 
72d053e71aSDaniel Kiss #endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
73d053e71aSDaniel Kiss 
ptrauth_keys_install_user(struct ptrauth_keys_user * keys)74b90e4839SPeter Collingbourne static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys)
75b90e4839SPeter Collingbourne {
76b90e4839SPeter Collingbourne 	if (system_supports_address_auth()) {
77b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APIB, keys->apib);
78b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APDA, keys->apda);
79b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APDB, keys->apdb);
80b90e4839SPeter Collingbourne 	}
81b90e4839SPeter Collingbourne 
82b90e4839SPeter Collingbourne 	if (system_supports_generic_auth())
83b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APGA, keys->apga);
84b90e4839SPeter Collingbourne }
85b90e4839SPeter Collingbourne 
ptrauth_keys_init_user(struct ptrauth_keys_user * keys)8691a1b6ccSKristina Martsenko static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
8775031975SMark Rutland {
8875031975SMark Rutland 	if (system_supports_address_auth()) {
8975031975SMark Rutland 		get_random_bytes(&keys->apia, sizeof(keys->apia));
9075031975SMark Rutland 		get_random_bytes(&keys->apib, sizeof(keys->apib));
9175031975SMark Rutland 		get_random_bytes(&keys->apda, sizeof(keys->apda));
9275031975SMark Rutland 		get_random_bytes(&keys->apdb, sizeof(keys->apdb));
9375031975SMark Rutland 	}
9475031975SMark Rutland 
9575031975SMark Rutland 	if (system_supports_generic_auth())
9675031975SMark Rutland 		get_random_bytes(&keys->apga, sizeof(keys->apga));
9775031975SMark Rutland 
98b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(keys);
99b90e4839SPeter Collingbourne }
10075031975SMark Rutland 
101ba830885SKristina Martsenko extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
102ba830885SKristina Martsenko 
10320169862SPeter Collingbourne extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
10420169862SPeter Collingbourne 				    unsigned long enabled);
10520169862SPeter Collingbourne extern int ptrauth_get_enabled_keys(struct task_struct *tsk);
10620169862SPeter Collingbourne 
ptrauth_enable(void)1077f624085SSrinivas Ramana static __always_inline void ptrauth_enable(void)
1087f624085SSrinivas Ramana {
1097f624085SSrinivas Ramana 	if (!system_supports_address_auth())
1107f624085SSrinivas Ramana 		return;
1117f624085SSrinivas Ramana 	sysreg_clear_set(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
1127f624085SSrinivas Ramana 					SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
1137f624085SSrinivas Ramana 	isb();
1147f624085SSrinivas Ramana }
1157f624085SSrinivas Ramana 
116b90e4839SPeter Collingbourne #define ptrauth_suspend_exit()                                                 \
117b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(&current->thread.keys_user)
118b90e4839SPeter Collingbourne 
11920169862SPeter Collingbourne #define ptrauth_thread_init_user()                                             \
12020169862SPeter Collingbourne 	do {                                                                   \
12120169862SPeter Collingbourne 		ptrauth_keys_init_user(&current->thread.keys_user);            \
12220169862SPeter Collingbourne 									       \
12320169862SPeter Collingbourne 		/* enable all keys */                                          \
12420169862SPeter Collingbourne 		if (system_supports_address_auth())                            \
125d2e0d8f9SPeter Collingbourne 			ptrauth_set_enabled_keys(current,                      \
126d2e0d8f9SPeter Collingbourne 						 PR_PAC_ENABLED_KEYS_MASK,     \
127d2e0d8f9SPeter Collingbourne 						 PR_PAC_ENABLED_KEYS_MASK);    \
12820169862SPeter Collingbourne 	} while (0)
12920169862SPeter Collingbourne 
130b90e4839SPeter Collingbourne #define ptrauth_thread_switch_user(tsk)                                        \
131b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(&(tsk)->thread.keys_user)
132b90e4839SPeter Collingbourne 
13375031975SMark Rutland #else /* CONFIG_ARM64_PTR_AUTH */
1347f624085SSrinivas Ramana #define ptrauth_enable()
135ba830885SKristina Martsenko #define ptrauth_prctl_reset_keys(tsk, arg)	(-EINVAL)
13620169862SPeter Collingbourne #define ptrauth_set_enabled_keys(tsk, keys, enabled)	(-EINVAL)
13720169862SPeter Collingbourne #define ptrauth_get_enabled_keys(tsk)	(-EINVAL)
138b90e4839SPeter Collingbourne #define ptrauth_suspend_exit()
13920169862SPeter Collingbourne #define ptrauth_thread_init_user()
140b90e4839SPeter Collingbourne #define ptrauth_thread_switch_user(tsk)
14175031975SMark Rutland #endif /* CONFIG_ARM64_PTR_AUTH */
14275031975SMark Rutland 
143d053e71aSDaniel Kiss #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
144d053e71aSDaniel Kiss #define ptrauth_thread_init_kernel(tsk)					\
145d053e71aSDaniel Kiss 	ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
146d053e71aSDaniel Kiss #define ptrauth_thread_switch_kernel(tsk)				\
147d053e71aSDaniel Kiss 	ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
148d053e71aSDaniel Kiss #else
149d053e71aSDaniel Kiss #define ptrauth_thread_init_kernel(tsk)
150d053e71aSDaniel Kiss #define ptrauth_thread_switch_kernel(tsk)
151d053e71aSDaniel Kiss #endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
152d053e71aSDaniel Kiss 
15375031975SMark Rutland #endif /* __ASM_POINTER_AUTH_H */
154