GNU Linux-libre 4.9.309-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/errno.h>
7 #include <linux/prctl.h>
8 #include <linux/sched.h>
9 #include <linux/thread_info.h>
10
11 #include <asm/cpufeature.h>
12
13 /*
14  * prctl interface for SSBD
15  */
16 static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
17 {
18         int state = arm64_get_ssbd_state();
19
20         /* Unsupported */
21         if (state == ARM64_SSBD_UNKNOWN)
22                 return -EINVAL;
23
24         /* Treat the unaffected/mitigated state separately */
25         if (state == ARM64_SSBD_MITIGATED) {
26                 switch (ctrl) {
27                 case PR_SPEC_ENABLE:
28                         return -EPERM;
29                 case PR_SPEC_DISABLE:
30                 case PR_SPEC_FORCE_DISABLE:
31                         return 0;
32                 }
33         }
34
35         /*
36          * Things are a bit backward here: the arm64 internal API
37          * *enables the mitigation* when the userspace API *disables
38          * speculation*. So much fun.
39          */
40         switch (ctrl) {
41         case PR_SPEC_ENABLE:
42                 /* If speculation is force disabled, enable is not allowed */
43                 if (state == ARM64_SSBD_FORCE_ENABLE ||
44                     task_spec_ssb_force_disable(task))
45                         return -EPERM;
46                 task_clear_spec_ssb_disable(task);
47                 clear_tsk_thread_flag(task, TIF_SSBD);
48                 break;
49         case PR_SPEC_DISABLE:
50                 if (state == ARM64_SSBD_FORCE_DISABLE)
51                         return -EPERM;
52                 task_set_spec_ssb_disable(task);
53                 set_tsk_thread_flag(task, TIF_SSBD);
54                 break;
55         case PR_SPEC_FORCE_DISABLE:
56                 if (state == ARM64_SSBD_FORCE_DISABLE)
57                         return -EPERM;
58                 task_set_spec_ssb_disable(task);
59                 task_set_spec_ssb_force_disable(task);
60                 set_tsk_thread_flag(task, TIF_SSBD);
61                 break;
62         default:
63                 return -ERANGE;
64         }
65
66         return 0;
67 }
68
69 int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
70                              unsigned long ctrl)
71 {
72         switch (which) {
73         case PR_SPEC_STORE_BYPASS:
74                 return ssbd_prctl_set(task, ctrl);
75         default:
76                 return -ENODEV;
77         }
78 }
79
80 static int ssbd_prctl_get(struct task_struct *task)
81 {
82         switch (arm64_get_ssbd_state()) {
83         case ARM64_SSBD_UNKNOWN:
84                 return -EINVAL;
85         case ARM64_SSBD_FORCE_ENABLE:
86                 return PR_SPEC_DISABLE;
87         case ARM64_SSBD_KERNEL:
88                 if (task_spec_ssb_force_disable(task))
89                         return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
90                 if (task_spec_ssb_disable(task))
91                         return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
92                 return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
93         case ARM64_SSBD_FORCE_DISABLE:
94                 return PR_SPEC_ENABLE;
95         default:
96                 return PR_SPEC_NOT_AFFECTED;
97         }
98 }
99
100 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
101 {
102         switch (which) {
103         case PR_SPEC_STORE_BYPASS:
104                 return ssbd_prctl_get(task);
105         default:
106                 return -ENODEV;
107         }
108 }