Loading...
Note: File does not exist in v6.8.
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
14static 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}
23early_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
31static 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
53int 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
78int 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}