Skip to content

Commit a56399b

Browse files
author
Fox Snowpatch
committed
1 parent 77dff0c commit a56399b

File tree

16 files changed

+823
-49
lines changed

16 files changed

+823
-49
lines changed

Documentation/arch/powerpc/dexcr.rst

+139-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,145 @@ state for a process.
3636
Configuration
3737
=============
3838

39-
The DEXCR is currently unconfigurable. All threads are run with the
40-
NPHIE aspect enabled.
39+
prctl
40+
-----
41+
42+
A process can control its own userspace DEXCR value using the
43+
``PR_PPC_GET_DEXCR`` and ``PR_PPC_SET_DEXCR`` pair of
44+
:manpage:`prctl(2)` commands. These calls have the form::
45+
46+
prctl(PR_PPC_GET_DEXCR, unsigned long which, 0, 0, 0);
47+
prctl(PR_PPC_SET_DEXCR, unsigned long which, unsigned long ctrl, 0, 0);
48+
49+
The possible 'which' and 'ctrl' values are as follows. Note there is no relation
50+
between the 'which' value and the DEXCR aspect's index.
51+
52+
.. flat-table::
53+
:header-rows: 1
54+
:widths: 2 7 1
55+
56+
* - ``prctl()`` which
57+
- Aspect name
58+
- Aspect index
59+
60+
* - ``PR_PPC_DEXCR_SBHE``
61+
- Speculative Branch Hint Enable (SBHE)
62+
- 0
63+
64+
* - ``PR_PPC_DEXCR_IBRTPD``
65+
- Indirect Branch Recurrent Target Prediction Disable (IBRTPD)
66+
- 3
67+
68+
* - ``PR_PPC_DEXCR_SRAPD``
69+
- Subroutine Return Address Prediction Disable (SRAPD)
70+
- 4
71+
72+
* - ``PR_PPC_DEXCR_NPHIE``
73+
- Non-Privileged Hash Instruction Enable (NPHIE)
74+
- 5
75+
76+
.. flat-table::
77+
:header-rows: 1
78+
:widths: 2 8
79+
80+
* - ``prctl()`` ctrl
81+
- Meaning
82+
83+
* - ``PR_PPC_DEXCR_CTRL_EDITABLE``
84+
- This aspect can be configured with PR_PPC_SET_DEXCR (get only)
85+
86+
* - ``PR_PPC_DEXCR_CTRL_SET``
87+
- This aspect is set / set this aspect
88+
89+
* - ``PR_PPC_DEXCR_CTRL_CLEAR``
90+
- This aspect is clear / clear this aspect
91+
92+
* - ``PR_PPC_DEXCR_CTRL_SET_ONEXEC``
93+
- This aspect will be set after exec / set this aspect after exec
94+
95+
* - ``PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC``
96+
- This aspect will be clear after exec / clear this aspect after exec
97+
98+
Note that
99+
100+
* which is a plain value, not a bitmask. Aspects must be worked with individually.
101+
102+
* ctrl is a bitmask. ``PR_PPC_GET_DEXCR`` returns both the current and onexec
103+
configuration. For example, ``PR_PPC_GET_DEXCR`` may return
104+
``PR_PPC_DEXCR_CTRL_EDITABLE | PR_PPC_DEXCR_CTRL_SET |
105+
PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC``. This would indicate the aspect is currently
106+
set, it will be cleared when you run exec, and you can change this with the
107+
``PR_PPC_SET_DEXCR`` prctl.
108+
109+
* The set/clear terminology refers to setting/clearing the bit in the DEXCR.
110+
For example::
111+
112+
prctl(PR_PPC_SET_DEXCR, PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_CTRL_SET, 0, 0);
113+
114+
will set the IBRTPD aspect bit in the DEXCR, causing indirect branch prediction
115+
to be disabled.
116+
117+
* The status returned by ``PR_PPC_GET_DEXCR`` represents what value the process
118+
would like applied. It does not include any alternative overrides, such as if
119+
the hypervisor is enforcing the aspect be set. To see the true DEXCR state
120+
software should read the appropriate SPRs directly.
121+
122+
* The aspect state when starting a process is copied from the parent's state on
123+
:manpage:`fork(2)`. The state is reset to a fixed value on
124+
:manpage:`execve(2)`. The PR_PPC_SET_DEXCR prctl() can control both of these
125+
values.
126+
127+
* The ``*_ONEXEC`` controls do not change the current process's DEXCR.
128+
129+
Use ``PR_PPC_SET_DEXCR`` with one of ``PR_PPC_DEXCR_CTRL_SET`` or
130+
``PR_PPC_DEXCR_CTRL_CLEAR`` to edit a given aspect.
131+
132+
Common error codes for both getting and setting the DEXCR are as follows:
133+
134+
.. flat-table::
135+
:header-rows: 1
136+
:widths: 2 8
137+
138+
* - Error
139+
- Meaning
140+
141+
* - ``EINVAL``
142+
- The DEXCR is not supported by the kernel.
143+
144+
* - ``ENODEV``
145+
- The aspect is not recognised by the kernel or not supported by the
146+
hardware.
147+
148+
``PR_PPC_SET_DEXCR`` may also report the following error codes:
149+
150+
.. flat-table::
151+
:header-rows: 1
152+
:widths: 2 8
153+
154+
* - Error
155+
- Meaning
156+
157+
* - ``EINVAL``
158+
- The ctrl value contains unrecognised flags.
159+
160+
* - ``EINVAL``
161+
- The ctrl value contains mutually conflicting flags (e.g.,
162+
``PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR``)
163+
164+
* - ``EPERM``
165+
- This aspect cannot be modified with prctl() (check for the
166+
PR_PPC_DEXCR_CTRL_EDITABLE flag with PR_PPC_GET_DEXCR).
167+
168+
* - ``EPERM``
169+
- The process does not have sufficient privilege to perform the operation.
170+
For example, clearing NPHIE on exec is a privileged operation (a process
171+
can still clear its own NPHIE aspect without privileges).
172+
173+
This interface allows a process to control its own DEXCR aspects, and also set
174+
the initial DEXCR value for any children in its process tree (up to the next
175+
child to use an ``*_ONEXEC`` control). This allows fine-grained control over the
176+
default value of the DEXCR, for example allowing containers to run with different
177+
default values.
41178

42179

43180
coredump and ptrace

arch/powerpc/include/asm/processor.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ struct thread_struct {
260260
unsigned long sier2;
261261
unsigned long sier3;
262262
unsigned long hashkeyr;
263-
263+
unsigned long dexcr;
264+
unsigned long dexcr_onexec; /* Reset value to load on exec */
264265
#endif
265266
};
266267

@@ -333,6 +334,16 @@ extern int set_endian(struct task_struct *tsk, unsigned int val);
333334
extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
334335
extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
335336

337+
#ifdef CONFIG_PPC_BOOK3S_64
338+
339+
#define PPC_GET_DEXCR_ASPECT(tsk, asp) get_dexcr_prctl((tsk), (asp))
340+
#define PPC_SET_DEXCR_ASPECT(tsk, asp, val) set_dexcr_prctl((tsk), (asp), (val))
341+
342+
int get_dexcr_prctl(struct task_struct *tsk, unsigned long asp);
343+
int set_dexcr_prctl(struct task_struct *tsk, unsigned long asp, unsigned long val);
344+
345+
#endif
346+
336347
extern void load_fp_state(struct thread_fp_state *fp);
337348
extern void store_fp_state(struct thread_fp_state *fp);
338349
extern void load_vr_state(struct thread_vr_state *vr);

arch/powerpc/kernel/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
8787
obj-$(CONFIG_PPC_DAWR) += dawr.o
8888
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
8989
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o
90+
obj-$(CONFIG_PPC_BOOK3S_64) += dexcr.o
9091
obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o
9192
obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_64e.o
9293
obj-$(CONFIG_PPC_BARRIER_NOSPEC) += security.o

arch/powerpc/kernel/dexcr.c

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

arch/powerpc/kernel/process.c

+17
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,9 @@ static inline void save_sprs(struct thread_struct *t)
11851185

11861186
if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE))
11871187
t->hashkeyr = mfspr(SPRN_HASHKEYR);
1188+
1189+
if (cpu_has_feature(CPU_FTR_ARCH_31))
1190+
t->dexcr = mfspr(SPRN_DEXCR);
11881191
#endif
11891192
}
11901193

@@ -1267,6 +1270,10 @@ static inline void restore_sprs(struct thread_struct *old_thread,
12671270
if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) &&
12681271
old_thread->hashkeyr != new_thread->hashkeyr)
12691272
mtspr(SPRN_HASHKEYR, new_thread->hashkeyr);
1273+
1274+
if (cpu_has_feature(CPU_FTR_ARCH_31) &&
1275+
old_thread->dexcr != new_thread->dexcr)
1276+
mtspr(SPRN_DEXCR, new_thread->dexcr);
12701277
#endif
12711278

12721279
}
@@ -1634,6 +1641,13 @@ void arch_setup_new_exec(void)
16341641
current->thread.regs->amr = default_amr;
16351642
current->thread.regs->iamr = default_iamr;
16361643
#endif
1644+
1645+
#ifdef CONFIG_PPC_BOOK3S_64
1646+
if (cpu_has_feature(CPU_FTR_ARCH_31)) {
1647+
current->thread.dexcr = current->thread.dexcr_onexec;
1648+
mtspr(SPRN_DEXCR, current->thread.dexcr);
1649+
}
1650+
#endif /* CONFIG_PPC_BOOK3S_64 */
16371651
}
16381652

16391653
#ifdef CONFIG_PPC64
@@ -1878,6 +1892,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
18781892
#ifdef CONFIG_PPC_BOOK3S_64
18791893
if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE))
18801894
p->thread.hashkeyr = current->thread.hashkeyr;
1895+
1896+
if (cpu_has_feature(CPU_FTR_ARCH_31))
1897+
p->thread.dexcr = mfspr(SPRN_DEXCR);
18811898
#endif
18821899
return 0;
18831900
}

arch/powerpc/kernel/ptrace/ptrace-view.c

+1-6
Original file line numberDiff line numberDiff line change
@@ -469,12 +469,7 @@ static int dexcr_get(struct task_struct *target, const struct user_regset *regse
469469
if (!cpu_has_feature(CPU_FTR_ARCH_31))
470470
return -ENODEV;
471471

472-
/*
473-
* The DEXCR is currently static across all CPUs, so we don't
474-
* store the target's value anywhere, but the static value
475-
* will also be correct.
476-
*/
477-
membuf_store(&to, (u64)lower_32_bits(DEXCR_INIT));
472+
membuf_store(&to, (u64)lower_32_bits(target->thread.dexcr));
478473

479474
/*
480475
* Technically the HDEXCR is per-cpu, but a hypervisor can't reasonably

include/uapi/linux/prctl.h

+16
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,20 @@ struct prctl_mm_map {
306306
# define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK 0xc
307307
# define PR_RISCV_V_VSTATE_CTRL_MASK 0x1f
308308

309+
/* PowerPC Dynamic Execution Control Register (DEXCR) controls */
310+
#define PR_PPC_GET_DEXCR 71
311+
#define PR_PPC_SET_DEXCR 72
312+
/* DEXCR aspect to act on */
313+
# define PR_PPC_DEXCR_SBHE 0 /* Speculative branch hint enable */
314+
# define PR_PPC_DEXCR_IBRTPD 1 /* Indirect branch recurrent target prediction disable */
315+
# define PR_PPC_DEXCR_SRAPD 2 /* Subroutine return address prediction disable */
316+
# define PR_PPC_DEXCR_NPHIE 3 /* Non-privileged hash instruction enable */
317+
/* Action to apply / return */
318+
# define PR_PPC_DEXCR_CTRL_EDITABLE (1UL << 0) /* This aspect can be modified with PR_PPC_SET_DEXCR */
319+
# define PR_PPC_DEXCR_CTRL_SET (1UL << 1) /* Set the aspect for this process */
320+
# define PR_PPC_DEXCR_CTRL_CLEAR (1UL << 2) /* Clear the aspect for this process */
321+
# define PR_PPC_DEXCR_CTRL_SET_ONEXEC (1UL << 3) /* Set the aspect on exec */
322+
# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC (1UL << 4) /* Clear the aspect on exec */
323+
# define PR_PPC_DEXCR_CTRL_MASK 0x1f
324+
309325
#endif /* _LINUX_PRCTL_H */

0 commit comments

Comments
 (0)