1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
4 */
5
6 #include <linux/compat.h>
7 #include <linux/errno.h>
8 #include <linux/prctl.h>
9 #include <linux/sched.h>
10 #include <linux/sched/task_stack.h>
11 #include <linux/thread_info.h>
12
13 #include <asm/compat.h>
14 #include <asm/cpufeature.h>
15
ssbd_ssbs_enable(struct task_struct * task)16 static void ssbd_ssbs_enable(struct task_struct *task)
17 {
18 u64 val = is_compat_thread(task_thread_info(task)) ?
19 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
20
21 task_pt_regs(task)->pstate |= val;
22 }
23
ssbd_ssbs_disable(struct task_struct * task)24 static void ssbd_ssbs_disable(struct task_struct *task)
25 {
26 u64 val = is_compat_thread(task_thread_info(task)) ?
27 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
28
29 task_pt_regs(task)->pstate &= ~val;
30 }
31
32 /*
33 * prctl interface for SSBD
34 */
ssbd_prctl_set(struct task_struct * task,unsigned long ctrl)35 static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
36 {
37 int state = arm64_get_ssbd_state();
38
39 /* Unsupported */
40 if (state == ARM64_SSBD_UNKNOWN)
41 return -EINVAL;
42
43 /* Treat the unaffected/mitigated state separately */
44 if (state == ARM64_SSBD_MITIGATED) {
45 switch (ctrl) {
46 case PR_SPEC_ENABLE:
47 return -EPERM;
48 case PR_SPEC_DISABLE:
49 case PR_SPEC_FORCE_DISABLE:
50 return 0;
51 }
52 }
53
54 /*
55 * Things are a bit backward here: the arm64 internal API
56 * *enables the mitigation* when the userspace API *disables
57 * speculation*. So much fun.
58 */
59 switch (ctrl) {
60 case PR_SPEC_ENABLE:
61 /* If speculation is force disabled, enable is not allowed */
62 if (state == ARM64_SSBD_FORCE_ENABLE ||
63 task_spec_ssb_force_disable(task))
64 return -EPERM;
65 task_clear_spec_ssb_disable(task);
66 clear_tsk_thread_flag(task, TIF_SSBD);
67 ssbd_ssbs_enable(task);
68 break;
69 case PR_SPEC_DISABLE:
70 if (state == ARM64_SSBD_FORCE_DISABLE)
71 return -EPERM;
72 task_set_spec_ssb_disable(task);
73 set_tsk_thread_flag(task, TIF_SSBD);
74 ssbd_ssbs_disable(task);
75 break;
76 case PR_SPEC_FORCE_DISABLE:
77 if (state == ARM64_SSBD_FORCE_DISABLE)
78 return -EPERM;
79 task_set_spec_ssb_disable(task);
80 task_set_spec_ssb_force_disable(task);
81 set_tsk_thread_flag(task, TIF_SSBD);
82 ssbd_ssbs_disable(task);
83 break;
84 default:
85 return -ERANGE;
86 }
87
88 return 0;
89 }
90
arch_prctl_spec_ctrl_set(struct task_struct * task,unsigned long which,unsigned long ctrl)91 int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
92 unsigned long ctrl)
93 {
94 switch (which) {
95 case PR_SPEC_STORE_BYPASS:
96 return ssbd_prctl_set(task, ctrl);
97 default:
98 return -ENODEV;
99 }
100 }
101
ssbd_prctl_get(struct task_struct * task)102 static int ssbd_prctl_get(struct task_struct *task)
103 {
104 switch (arm64_get_ssbd_state()) {
105 case ARM64_SSBD_UNKNOWN:
106 return -EINVAL;
107 case ARM64_SSBD_FORCE_ENABLE:
108 return PR_SPEC_DISABLE;
109 case ARM64_SSBD_KERNEL:
110 if (task_spec_ssb_force_disable(task))
111 return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
112 if (task_spec_ssb_disable(task))
113 return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
114 return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
115 case ARM64_SSBD_FORCE_DISABLE:
116 return PR_SPEC_ENABLE;
117 default:
118 return PR_SPEC_NOT_AFFECTED;
119 }
120 }
121
arch_prctl_spec_ctrl_get(struct task_struct * task,unsigned long which)122 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
123 {
124 switch (which) {
125 case PR_SPEC_STORE_BYPASS:
126 return ssbd_prctl_get(task);
127 default:
128 return -ENODEV;
129 }
130 }
131