175031975SMark Rutland // 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>
675031975SMark Rutland #include <linux/random.h>
775031975SMark Rutland 
875031975SMark Rutland #include <asm/cpufeature.h>
9ec6e822dSMark Rutland #include <asm/memory.h>
1075031975SMark Rutland #include <asm/sysreg.h>
1175031975SMark Rutland 
1275031975SMark Rutland #ifdef CONFIG_ARM64_PTR_AUTH
1375031975SMark Rutland /*
1475031975SMark Rutland  * Each key is a 128-bit quantity which is split across a pair of 64-bit
1575031975SMark Rutland  * registers (Lo and Hi).
1675031975SMark Rutland  */
1775031975SMark Rutland struct ptrauth_key {
1875031975SMark Rutland 	unsigned long lo, hi;
1975031975SMark Rutland };
2075031975SMark Rutland 
2175031975SMark Rutland /*
2275031975SMark Rutland  * We give each process its own keys, which are shared by all threads. The keys
2375031975SMark Rutland  * are inherited upon fork(), and reinitialised upon exec*().
2475031975SMark Rutland  */
2575031975SMark Rutland struct ptrauth_keys {
2675031975SMark Rutland 	struct ptrauth_key apia;
2775031975SMark Rutland 	struct ptrauth_key apib;
2875031975SMark Rutland 	struct ptrauth_key apda;
2975031975SMark Rutland 	struct ptrauth_key apdb;
3075031975SMark Rutland 	struct ptrauth_key apga;
3175031975SMark Rutland };
3275031975SMark Rutland 
3375031975SMark Rutland static inline void ptrauth_keys_init(struct ptrauth_keys *keys)
3475031975SMark Rutland {
3575031975SMark Rutland 	if (system_supports_address_auth()) {
3675031975SMark Rutland 		get_random_bytes(&keys->apia, sizeof(keys->apia));
3775031975SMark Rutland 		get_random_bytes(&keys->apib, sizeof(keys->apib));
3875031975SMark Rutland 		get_random_bytes(&keys->apda, sizeof(keys->apda));
3975031975SMark Rutland 		get_random_bytes(&keys->apdb, sizeof(keys->apdb));
4075031975SMark Rutland 	}
4175031975SMark Rutland 
4275031975SMark Rutland 	if (system_supports_generic_auth())
4375031975SMark Rutland 		get_random_bytes(&keys->apga, sizeof(keys->apga));
4475031975SMark Rutland }
4575031975SMark Rutland 
4675031975SMark Rutland #define __ptrauth_key_install(k, v)				\
4775031975SMark Rutland do {								\
4875031975SMark Rutland 	struct ptrauth_key __pki_v = (v);			\
4975031975SMark Rutland 	write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1);	\
5075031975SMark Rutland 	write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);	\
5175031975SMark Rutland } while (0)
5275031975SMark Rutland 
5375031975SMark Rutland static inline void ptrauth_keys_switch(struct ptrauth_keys *keys)
5475031975SMark Rutland {
5575031975SMark Rutland 	if (system_supports_address_auth()) {
5675031975SMark Rutland 		__ptrauth_key_install(APIA, keys->apia);
5775031975SMark Rutland 		__ptrauth_key_install(APIB, keys->apib);
5875031975SMark Rutland 		__ptrauth_key_install(APDA, keys->apda);
5975031975SMark Rutland 		__ptrauth_key_install(APDB, keys->apdb);
6075031975SMark Rutland 	}
6175031975SMark Rutland 
6275031975SMark Rutland 	if (system_supports_generic_auth())
6375031975SMark Rutland 		__ptrauth_key_install(APGA, keys->apga);
6475031975SMark Rutland }
6575031975SMark Rutland 
66ba830885SKristina Martsenko extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
67ba830885SKristina Martsenko 
68ec6e822dSMark Rutland /*
69ec6e822dSMark Rutland  * The EL0 pointer bits used by a pointer authentication code.
70ec6e822dSMark Rutland  * This is dependent on TBI0 being enabled, or bits 63:56 would also apply.
71ec6e822dSMark Rutland  */
72ec6e822dSMark Rutland #define ptrauth_user_pac_mask()	GENMASK(54, vabits_user)
73ec6e822dSMark Rutland 
74ccc43810SMark Rutland /* Only valid for EL0 TTBR0 instruction pointers */
75ccc43810SMark Rutland static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr)
76ccc43810SMark Rutland {
77ccc43810SMark Rutland 	return ptr & ~ptrauth_user_pac_mask();
78ccc43810SMark Rutland }
79ccc43810SMark Rutland 
8075031975SMark Rutland #define ptrauth_thread_init_user(tsk)					\
8175031975SMark Rutland do {									\
8275031975SMark Rutland 	struct task_struct *__ptiu_tsk = (tsk);				\
8375031975SMark Rutland 	ptrauth_keys_init(&__ptiu_tsk->thread_info.keys_user);		\
8475031975SMark Rutland 	ptrauth_keys_switch(&__ptiu_tsk->thread_info.keys_user);	\
8575031975SMark Rutland } while (0)
8675031975SMark Rutland 
8775031975SMark Rutland #define ptrauth_thread_switch(tsk)	\
8875031975SMark Rutland 	ptrauth_keys_switch(&(tsk)->thread_info.keys_user)
8975031975SMark Rutland 
9075031975SMark Rutland #else /* CONFIG_ARM64_PTR_AUTH */
91ba830885SKristina Martsenko #define ptrauth_prctl_reset_keys(tsk, arg)	(-EINVAL)
92ccc43810SMark Rutland #define ptrauth_strip_insn_pac(lr)	(lr)
9375031975SMark Rutland #define ptrauth_thread_init_user(tsk)
9475031975SMark Rutland #define ptrauth_thread_switch(tsk)
9575031975SMark Rutland #endif /* CONFIG_ARM64_PTR_AUTH */
9675031975SMark Rutland 
9775031975SMark Rutland #endif /* __ASM_POINTER_AUTH_H */
98