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*d2e0d8f9SPeter Collingbourne #define PR_PAC_ENABLED_KEYS_MASK                                               \
14*d2e0d8f9SPeter Collingbourne 	(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)
15*d2e0d8f9SPeter Collingbourne 
1675031975SMark Rutland #ifdef CONFIG_ARM64_PTR_AUTH
1775031975SMark Rutland /*
1875031975SMark Rutland  * Each key is a 128-bit quantity which is split across a pair of 64-bit
1975031975SMark Rutland  * registers (Lo and Hi).
2075031975SMark Rutland  */
2175031975SMark Rutland struct ptrauth_key {
2275031975SMark Rutland 	unsigned long lo, hi;
2375031975SMark Rutland };
2475031975SMark Rutland 
2575031975SMark Rutland /*
2675031975SMark Rutland  * We give each process its own keys, which are shared by all threads. The keys
2775031975SMark Rutland  * are inherited upon fork(), and reinitialised upon exec*().
2875031975SMark Rutland  */
2991a1b6ccSKristina Martsenko struct ptrauth_keys_user {
3075031975SMark Rutland 	struct ptrauth_key apia;
3175031975SMark Rutland 	struct ptrauth_key apib;
3275031975SMark Rutland 	struct ptrauth_key apda;
3375031975SMark Rutland 	struct ptrauth_key apdb;
3475031975SMark Rutland 	struct ptrauth_key apga;
3575031975SMark Rutland };
3675031975SMark Rutland 
37b90e4839SPeter Collingbourne #define __ptrauth_key_install_nosync(k, v)			\
38b90e4839SPeter Collingbourne do {								\
39b90e4839SPeter Collingbourne 	struct ptrauth_key __pki_v = (v);			\
40b90e4839SPeter Collingbourne 	write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1);	\
41b90e4839SPeter Collingbourne 	write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);	\
42b90e4839SPeter Collingbourne } while (0)
43b90e4839SPeter Collingbourne 
44d053e71aSDaniel Kiss #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
45d053e71aSDaniel Kiss 
46d053e71aSDaniel Kiss struct ptrauth_keys_kernel {
47d053e71aSDaniel Kiss 	struct ptrauth_key apia;
48d053e71aSDaniel Kiss };
49d053e71aSDaniel Kiss 
50d053e71aSDaniel Kiss static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
51d053e71aSDaniel Kiss {
52d053e71aSDaniel Kiss 	if (system_supports_address_auth())
53d053e71aSDaniel Kiss 		get_random_bytes(&keys->apia, sizeof(keys->apia));
54d053e71aSDaniel Kiss }
55d053e71aSDaniel Kiss 
56d053e71aSDaniel Kiss static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
57d053e71aSDaniel Kiss {
58d053e71aSDaniel Kiss 	if (!system_supports_address_auth())
59d053e71aSDaniel Kiss 		return;
60d053e71aSDaniel Kiss 
61d053e71aSDaniel Kiss 	__ptrauth_key_install_nosync(APIA, keys->apia);
62d053e71aSDaniel Kiss 	isb();
63d053e71aSDaniel Kiss }
64d053e71aSDaniel Kiss 
65d053e71aSDaniel Kiss #endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
66d053e71aSDaniel Kiss 
67b90e4839SPeter Collingbourne static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys)
68b90e4839SPeter Collingbourne {
69b90e4839SPeter Collingbourne 	if (system_supports_address_auth()) {
70b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APIB, keys->apib);
71b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APDA, keys->apda);
72b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APDB, keys->apdb);
73b90e4839SPeter Collingbourne 	}
74b90e4839SPeter Collingbourne 
75b90e4839SPeter Collingbourne 	if (system_supports_generic_auth())
76b90e4839SPeter Collingbourne 		__ptrauth_key_install_nosync(APGA, keys->apga);
77b90e4839SPeter Collingbourne }
78b90e4839SPeter Collingbourne 
7991a1b6ccSKristina Martsenko static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
8075031975SMark Rutland {
8175031975SMark Rutland 	if (system_supports_address_auth()) {
8275031975SMark Rutland 		get_random_bytes(&keys->apia, sizeof(keys->apia));
8375031975SMark Rutland 		get_random_bytes(&keys->apib, sizeof(keys->apib));
8475031975SMark Rutland 		get_random_bytes(&keys->apda, sizeof(keys->apda));
8575031975SMark Rutland 		get_random_bytes(&keys->apdb, sizeof(keys->apdb));
8675031975SMark Rutland 	}
8775031975SMark Rutland 
8875031975SMark Rutland 	if (system_supports_generic_auth())
8975031975SMark Rutland 		get_random_bytes(&keys->apga, sizeof(keys->apga));
9075031975SMark Rutland 
91b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(keys);
92b90e4839SPeter Collingbourne }
9375031975SMark Rutland 
94ba830885SKristina Martsenko extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
95ba830885SKristina Martsenko 
9620169862SPeter Collingbourne extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
9720169862SPeter Collingbourne 				    unsigned long enabled);
9820169862SPeter Collingbourne extern int ptrauth_get_enabled_keys(struct task_struct *tsk);
9920169862SPeter Collingbourne 
100ccc43810SMark Rutland static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr)
101ccc43810SMark Rutland {
102689eae42SAmit Daniel Kachhap 	return ptrauth_clear_pac(ptr);
103ccc43810SMark Rutland }
104ccc43810SMark Rutland 
1057f624085SSrinivas Ramana static __always_inline void ptrauth_enable(void)
1067f624085SSrinivas Ramana {
1077f624085SSrinivas Ramana 	if (!system_supports_address_auth())
1087f624085SSrinivas Ramana 		return;
1097f624085SSrinivas Ramana 	sysreg_clear_set(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
1107f624085SSrinivas Ramana 					SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
1117f624085SSrinivas Ramana 	isb();
1127f624085SSrinivas Ramana }
1137f624085SSrinivas Ramana 
114b90e4839SPeter Collingbourne #define ptrauth_suspend_exit()                                                 \
115b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(&current->thread.keys_user)
116b90e4839SPeter Collingbourne 
11720169862SPeter Collingbourne #define ptrauth_thread_init_user()                                             \
11820169862SPeter Collingbourne 	do {                                                                   \
11920169862SPeter Collingbourne 		ptrauth_keys_init_user(&current->thread.keys_user);            \
12020169862SPeter Collingbourne 									       \
12120169862SPeter Collingbourne 		/* enable all keys */                                          \
12220169862SPeter Collingbourne 		if (system_supports_address_auth())                            \
123*d2e0d8f9SPeter Collingbourne 			ptrauth_set_enabled_keys(current,                      \
124*d2e0d8f9SPeter Collingbourne 						 PR_PAC_ENABLED_KEYS_MASK,     \
125*d2e0d8f9SPeter Collingbourne 						 PR_PAC_ENABLED_KEYS_MASK);    \
12620169862SPeter Collingbourne 	} while (0)
12720169862SPeter Collingbourne 
128b90e4839SPeter Collingbourne #define ptrauth_thread_switch_user(tsk)                                        \
129b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(&(tsk)->thread.keys_user)
130b90e4839SPeter Collingbourne 
13175031975SMark Rutland #else /* CONFIG_ARM64_PTR_AUTH */
1327f624085SSrinivas Ramana #define ptrauth_enable()
133ba830885SKristina Martsenko #define ptrauth_prctl_reset_keys(tsk, arg)	(-EINVAL)
13420169862SPeter Collingbourne #define ptrauth_set_enabled_keys(tsk, keys, enabled)	(-EINVAL)
13520169862SPeter Collingbourne #define ptrauth_get_enabled_keys(tsk)	(-EINVAL)
136ccc43810SMark Rutland #define ptrauth_strip_insn_pac(lr)	(lr)
137b90e4839SPeter Collingbourne #define ptrauth_suspend_exit()
13820169862SPeter Collingbourne #define ptrauth_thread_init_user()
139b90e4839SPeter Collingbourne #define ptrauth_thread_switch_user(tsk)
14075031975SMark Rutland #endif /* CONFIG_ARM64_PTR_AUTH */
14175031975SMark Rutland 
142d053e71aSDaniel Kiss #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
143d053e71aSDaniel Kiss #define ptrauth_thread_init_kernel(tsk)					\
144d053e71aSDaniel Kiss 	ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
145d053e71aSDaniel Kiss #define ptrauth_thread_switch_kernel(tsk)				\
146d053e71aSDaniel Kiss 	ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
147d053e71aSDaniel Kiss #else
148d053e71aSDaniel Kiss #define ptrauth_thread_init_kernel(tsk)
149d053e71aSDaniel Kiss #define ptrauth_thread_switch_kernel(tsk)
150d053e71aSDaniel Kiss #endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
151d053e71aSDaniel Kiss 
15275031975SMark Rutland #endif /* __ASM_POINTER_AUTH_H */
153