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