GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / arm64 / kernel / ssbd.c
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
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
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  */
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
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
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
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 }