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