xref: /linux/arch/powerpc/kernel/dexcr.c (revision ff2632d7d08edc11e8bd0629e9fcfebab25c78b4)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <linux/capability.h>
4 #include <linux/cpu.h>
5 #include <linux/init.h>
6 #include <linux/prctl.h>
7 #include <linux/sched.h>
8 
9 #include <asm/cpu_has_feature.h>
10 #include <asm/cputable.h>
11 #include <asm/processor.h>
12 #include <asm/reg.h>
13 
init_task_dexcr(void)14 static int __init init_task_dexcr(void)
15 {
16 	if (!early_cpu_has_feature(CPU_FTR_ARCH_31))
17 		return 0;
18 
19 	current->thread.dexcr_onexec = mfspr(SPRN_DEXCR);
20 
21 	return 0;
22 }
early_initcall(init_task_dexcr)23 early_initcall(init_task_dexcr)
24 
25 /* Allow thread local configuration of these by default */
26 #define DEXCR_PRCTL_EDITABLE ( \
27 	DEXCR_PR_IBRTPD | \
28 	DEXCR_PR_SRAPD | \
29 	DEXCR_PR_NPHIE)
30 
31 static int prctl_to_aspect(unsigned long which, unsigned int *aspect)
32 {
33 	switch (which) {
34 	case PR_PPC_DEXCR_SBHE:
35 		*aspect = DEXCR_PR_SBHE;
36 		break;
37 	case PR_PPC_DEXCR_IBRTPD:
38 		*aspect = DEXCR_PR_IBRTPD;
39 		break;
40 	case PR_PPC_DEXCR_SRAPD:
41 		*aspect = DEXCR_PR_SRAPD;
42 		break;
43 	case PR_PPC_DEXCR_NPHIE:
44 		*aspect = DEXCR_PR_NPHIE;
45 		break;
46 	default:
47 		return -ENODEV;
48 	}
49 
50 	return 0;
51 }
52 
get_dexcr_prctl(struct task_struct * task,unsigned long which)53 int get_dexcr_prctl(struct task_struct *task, unsigned long which)
54 {
55 	unsigned int aspect;
56 	int ret;
57 
58 	ret = prctl_to_aspect(which, &aspect);
59 	if (ret)
60 		return ret;
61 
62 	if (aspect & DEXCR_PRCTL_EDITABLE)
63 		ret |= PR_PPC_DEXCR_CTRL_EDITABLE;
64 
65 	if (aspect & mfspr(SPRN_DEXCR))
66 		ret |= PR_PPC_DEXCR_CTRL_SET;
67 	else
68 		ret |= PR_PPC_DEXCR_CTRL_CLEAR;
69 
70 	if (aspect & task->thread.dexcr_onexec)
71 		ret |= PR_PPC_DEXCR_CTRL_SET_ONEXEC;
72 	else
73 		ret |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC;
74 
75 	return ret;
76 }
77 
set_dexcr_prctl(struct task_struct * task,unsigned long which,unsigned long ctrl)78 int set_dexcr_prctl(struct task_struct *task, unsigned long which, unsigned long ctrl)
79 {
80 	unsigned long dexcr;
81 	unsigned int aspect;
82 	int err = 0;
83 
84 	err = prctl_to_aspect(which, &aspect);
85 	if (err)
86 		return err;
87 
88 	if (!(aspect & DEXCR_PRCTL_EDITABLE))
89 		return -EPERM;
90 
91 	if (ctrl & ~PR_PPC_DEXCR_CTRL_MASK)
92 		return -EINVAL;
93 
94 	if (ctrl & PR_PPC_DEXCR_CTRL_SET && ctrl & PR_PPC_DEXCR_CTRL_CLEAR)
95 		return -EINVAL;
96 
97 	if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC && ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC)
98 		return -EINVAL;
99 
100 	/*
101 	 * We do not want an unprivileged process being able to disable
102 	 * a setuid process's hash check instructions
103 	 */
104 	if (aspect == DEXCR_PR_NPHIE &&
105 	    ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC &&
106 	    !capable(CAP_SYS_ADMIN))
107 		return -EPERM;
108 
109 	dexcr = mfspr(SPRN_DEXCR);
110 
111 	if (ctrl & PR_PPC_DEXCR_CTRL_SET)
112 		dexcr |= aspect;
113 	else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR)
114 		dexcr &= ~aspect;
115 
116 	if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC)
117 		task->thread.dexcr_onexec |= aspect;
118 	else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC)
119 		task->thread.dexcr_onexec &= ~aspect;
120 
121 	mtspr(SPRN_DEXCR, dexcr);
122 
123 	return 0;
124 }
125