xref: /openbmc/linux/arch/arm64/kernel/pointer_auth.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1ba830885SKristina Martsenko // SPDX-License-Identifier: GPL-2.0
2ba830885SKristina Martsenko 
34b7a6ce7SPeter Collingbourne #include <linux/compat.h>
4ba830885SKristina Martsenko #include <linux/errno.h>
5ba830885SKristina Martsenko #include <linux/prctl.h>
6ba830885SKristina Martsenko #include <linux/random.h>
7ba830885SKristina Martsenko #include <linux/sched.h>
8ba830885SKristina Martsenko #include <asm/cpufeature.h>
9ba830885SKristina Martsenko #include <asm/pointer_auth.h>
10ba830885SKristina Martsenko 
ptrauth_prctl_reset_keys(struct task_struct * tsk,unsigned long arg)11ba830885SKristina Martsenko int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
12ba830885SKristina Martsenko {
1391a1b6ccSKristina Martsenko 	struct ptrauth_keys_user *keys = &tsk->thread.keys_user;
14ba830885SKristina Martsenko 	unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
15ba830885SKristina Martsenko 				      PR_PAC_APDAKEY | PR_PAC_APDBKEY;
16ba830885SKristina Martsenko 	unsigned long key_mask = addr_key_mask | PR_PAC_APGAKEY;
17ba830885SKristina Martsenko 
18ba830885SKristina Martsenko 	if (!system_supports_address_auth() && !system_supports_generic_auth())
19ba830885SKristina Martsenko 		return -EINVAL;
20ba830885SKristina Martsenko 
214b7a6ce7SPeter Collingbourne 	if (is_compat_thread(task_thread_info(tsk)))
224b7a6ce7SPeter Collingbourne 		return -EINVAL;
234b7a6ce7SPeter Collingbourne 
24ba830885SKristina Martsenko 	if (!arg) {
2591a1b6ccSKristina Martsenko 		ptrauth_keys_init_user(keys);
26ba830885SKristina Martsenko 		return 0;
27ba830885SKristina Martsenko 	}
28ba830885SKristina Martsenko 
29ba830885SKristina Martsenko 	if (arg & ~key_mask)
30ba830885SKristina Martsenko 		return -EINVAL;
31ba830885SKristina Martsenko 
32ba830885SKristina Martsenko 	if (((arg & addr_key_mask) && !system_supports_address_auth()) ||
33ba830885SKristina Martsenko 	    ((arg & PR_PAC_APGAKEY) && !system_supports_generic_auth()))
34ba830885SKristina Martsenko 		return -EINVAL;
35ba830885SKristina Martsenko 
36ba830885SKristina Martsenko 	if (arg & PR_PAC_APIAKEY)
37ba830885SKristina Martsenko 		get_random_bytes(&keys->apia, sizeof(keys->apia));
38ba830885SKristina Martsenko 	if (arg & PR_PAC_APIBKEY)
39ba830885SKristina Martsenko 		get_random_bytes(&keys->apib, sizeof(keys->apib));
40ba830885SKristina Martsenko 	if (arg & PR_PAC_APDAKEY)
41ba830885SKristina Martsenko 		get_random_bytes(&keys->apda, sizeof(keys->apda));
42ba830885SKristina Martsenko 	if (arg & PR_PAC_APDBKEY)
43ba830885SKristina Martsenko 		get_random_bytes(&keys->apdb, sizeof(keys->apdb));
44ba830885SKristina Martsenko 	if (arg & PR_PAC_APGAKEY)
45ba830885SKristina Martsenko 		get_random_bytes(&keys->apga, sizeof(keys->apga));
46b90e4839SPeter Collingbourne 	ptrauth_keys_install_user(keys);
47ba830885SKristina Martsenko 
48ba830885SKristina Martsenko 	return 0;
49ba830885SKristina Martsenko }
5020169862SPeter Collingbourne 
arg_to_enxx_mask(unsigned long arg)5120169862SPeter Collingbourne static u64 arg_to_enxx_mask(unsigned long arg)
5220169862SPeter Collingbourne {
5320169862SPeter Collingbourne 	u64 sctlr_enxx_mask = 0;
5420169862SPeter Collingbourne 
5520169862SPeter Collingbourne 	WARN_ON(arg & ~PR_PAC_ENABLED_KEYS_MASK);
5620169862SPeter Collingbourne 	if (arg & PR_PAC_APIAKEY)
5720169862SPeter Collingbourne 		sctlr_enxx_mask |= SCTLR_ELx_ENIA;
5820169862SPeter Collingbourne 	if (arg & PR_PAC_APIBKEY)
5920169862SPeter Collingbourne 		sctlr_enxx_mask |= SCTLR_ELx_ENIB;
6020169862SPeter Collingbourne 	if (arg & PR_PAC_APDAKEY)
6120169862SPeter Collingbourne 		sctlr_enxx_mask |= SCTLR_ELx_ENDA;
6220169862SPeter Collingbourne 	if (arg & PR_PAC_APDBKEY)
6320169862SPeter Collingbourne 		sctlr_enxx_mask |= SCTLR_ELx_ENDB;
6420169862SPeter Collingbourne 	return sctlr_enxx_mask;
6520169862SPeter Collingbourne }
6620169862SPeter Collingbourne 
ptrauth_set_enabled_keys(struct task_struct * tsk,unsigned long keys,unsigned long enabled)6720169862SPeter Collingbourne int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
6820169862SPeter Collingbourne 			     unsigned long enabled)
6920169862SPeter Collingbourne {
70*d2e0d8f9SPeter Collingbourne 	u64 sctlr;
7120169862SPeter Collingbourne 
7220169862SPeter Collingbourne 	if (!system_supports_address_auth())
7320169862SPeter Collingbourne 		return -EINVAL;
7420169862SPeter Collingbourne 
7520169862SPeter Collingbourne 	if (is_compat_thread(task_thread_info(tsk)))
7620169862SPeter Collingbourne 		return -EINVAL;
7720169862SPeter Collingbourne 
7820169862SPeter Collingbourne 	if ((keys & ~PR_PAC_ENABLED_KEYS_MASK) || (enabled & ~keys))
7920169862SPeter Collingbourne 		return -EINVAL;
8020169862SPeter Collingbourne 
81*d2e0d8f9SPeter Collingbourne 	preempt_disable();
82*d2e0d8f9SPeter Collingbourne 	sctlr = tsk->thread.sctlr_user;
8320169862SPeter Collingbourne 	sctlr &= ~arg_to_enxx_mask(keys);
8420169862SPeter Collingbourne 	sctlr |= arg_to_enxx_mask(enabled);
8520169862SPeter Collingbourne 	tsk->thread.sctlr_user = sctlr;
86*d2e0d8f9SPeter Collingbourne 	if (tsk == current)
87*d2e0d8f9SPeter Collingbourne 		update_sctlr_el1(sctlr);
88*d2e0d8f9SPeter Collingbourne 	preempt_enable();
8920169862SPeter Collingbourne 
9020169862SPeter Collingbourne 	return 0;
9120169862SPeter Collingbourne }
9220169862SPeter Collingbourne 
ptrauth_get_enabled_keys(struct task_struct * tsk)9320169862SPeter Collingbourne int ptrauth_get_enabled_keys(struct task_struct *tsk)
9420169862SPeter Collingbourne {
9520169862SPeter Collingbourne 	int retval = 0;
9620169862SPeter Collingbourne 
9720169862SPeter Collingbourne 	if (!system_supports_address_auth())
9820169862SPeter Collingbourne 		return -EINVAL;
9920169862SPeter Collingbourne 
10020169862SPeter Collingbourne 	if (is_compat_thread(task_thread_info(tsk)))
10120169862SPeter Collingbourne 		return -EINVAL;
10220169862SPeter Collingbourne 
10320169862SPeter Collingbourne 	if (tsk->thread.sctlr_user & SCTLR_ELx_ENIA)
10420169862SPeter Collingbourne 		retval |= PR_PAC_APIAKEY;
10520169862SPeter Collingbourne 	if (tsk->thread.sctlr_user & SCTLR_ELx_ENIB)
10620169862SPeter Collingbourne 		retval |= PR_PAC_APIBKEY;
10720169862SPeter Collingbourne 	if (tsk->thread.sctlr_user & SCTLR_ELx_ENDA)
10820169862SPeter Collingbourne 		retval |= PR_PAC_APDAKEY;
10920169862SPeter Collingbourne 	if (tsk->thread.sctlr_user & SCTLR_ELx_ENDB)
11020169862SPeter Collingbourne 		retval |= PR_PAC_APDBKEY;
11120169862SPeter Collingbourne 
11220169862SPeter Collingbourne 	return retval;
11320169862SPeter Collingbourne }
114