~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/security/spectre_v2.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 
  3 /*
  4  * Copyright 2018-2019 IBM Corporation.
  5  */
  6 
  7 #define __SANE_USERSPACE_TYPES__
  8 
  9 #include <sys/types.h>
 10 #include <stdint.h>
 11 #include <malloc.h>
 12 #include <unistd.h>
 13 #include <stdlib.h>
 14 #include <string.h>
 15 #include <stdio.h>
 16 #include <sys/prctl.h>
 17 #include "utils.h"
 18 
 19 #include "../pmu/event.h"
 20 
 21 
 22 extern void pattern_cache_loop(void);
 23 extern void indirect_branch_loop(void);
 24 
 25 static int do_count_loop(struct event *events, bool is_p9, s64 *miss_percent)
 26 {
 27         u64 pred, mpred;
 28 
 29         prctl(PR_TASK_PERF_EVENTS_ENABLE);
 30 
 31         if (is_p9)
 32                 pattern_cache_loop();
 33         else
 34                 indirect_branch_loop();
 35 
 36         prctl(PR_TASK_PERF_EVENTS_DISABLE);
 37 
 38         event_read(&events[0]);
 39         event_read(&events[1]);
 40 
 41         // We could scale all the events by running/enabled but we're lazy
 42         // As long as the PMU is uncontended they should all run
 43         FAIL_IF(events[0].result.running != events[0].result.enabled);
 44         FAIL_IF(events[1].result.running != events[1].result.enabled);
 45 
 46         pred =  events[0].result.value;
 47         mpred = events[1].result.value;
 48 
 49         if (is_p9) {
 50                 event_read(&events[2]);
 51                 event_read(&events[3]);
 52                 FAIL_IF(events[2].result.running != events[2].result.enabled);
 53                 FAIL_IF(events[3].result.running != events[3].result.enabled);
 54 
 55                 pred  += events[2].result.value;
 56                 mpred += events[3].result.value;
 57         }
 58 
 59         *miss_percent = 100 * mpred / pred;
 60 
 61         return 0;
 62 }
 63 
 64 static void setup_event(struct event *e, u64 config, char *name)
 65 {
 66         event_init_named(e, config, name);
 67 
 68         e->attr.disabled = 1;
 69         e->attr.exclude_kernel = 1;
 70         e->attr.exclude_hv = 1;
 71         e->attr.exclude_idle = 1;
 72 }
 73 
 74 enum spectre_v2_state {
 75         VULNERABLE = 0,
 76         UNKNOWN = 1,            // Works with FAIL_IF()
 77         NOT_AFFECTED,
 78         BRANCH_SERIALISATION,
 79         COUNT_CACHE_DISABLED,
 80         COUNT_CACHE_FLUSH_SW,
 81         COUNT_CACHE_FLUSH_HW,
 82         BTB_FLUSH,
 83 };
 84 
 85 static enum spectre_v2_state get_sysfs_state(void)
 86 {
 87         enum spectre_v2_state state = UNKNOWN;
 88         char buf[256];
 89         int len;
 90 
 91         memset(buf, 0, sizeof(buf));
 92         FAIL_IF(read_sysfs_file("devices/system/cpu/vulnerabilities/spectre_v2", buf, sizeof(buf)));
 93 
 94         // Make sure it's NULL terminated
 95         buf[sizeof(buf) - 1] = '\0';
 96 
 97         // Trim the trailing newline
 98         len = strlen(buf);
 99         FAIL_IF(len < 1);
100         buf[len - 1] = '\0';
101 
102         printf("sysfs reports: '%s'\n", buf);
103 
104         // Order matters
105         if (strstr(buf, "Vulnerable"))
106                 state = VULNERABLE;
107         else if (strstr(buf, "Not affected"))
108                 state = NOT_AFFECTED;
109         else if (strstr(buf, "Indirect branch serialisation (kernel only)"))
110                 state = BRANCH_SERIALISATION;
111         else if (strstr(buf, "Indirect branch cache disabled"))
112                 state = COUNT_CACHE_DISABLED;
113         else if (strstr(buf, "Software count cache flush (hardware accelerated)"))
114                 state = COUNT_CACHE_FLUSH_HW;
115         else if (strstr(buf, "Software count cache flush"))
116                 state = COUNT_CACHE_FLUSH_SW;
117         else if (strstr(buf, "Branch predictor state flush"))
118                 state = BTB_FLUSH;
119 
120         return state;
121 }
122 
123 #define PM_BR_PRED_CCACHE       0x040a4 // P8 + P9
124 #define PM_BR_MPRED_CCACHE      0x040ac // P8 + P9
125 #define PM_BR_PRED_PCACHE       0x048a0 // P9 only
126 #define PM_BR_MPRED_PCACHE      0x048b0 // P9 only
127 
128 int spectre_v2_test(void)
129 {
130         enum spectre_v2_state state;
131         struct event events[4];
132         s64 miss_percent;
133         bool is_p9;
134 
135         // The PMU events we use only work on Power8 or later
136         SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
137 
138         state = get_sysfs_state();
139         if (state == UNKNOWN) {
140                 printf("Error: couldn't determine spectre_v2 mitigation state?\n");
141                 return -1;
142         }
143 
144         memset(events, 0, sizeof(events));
145 
146         setup_event(&events[0], PM_BR_PRED_CCACHE,  "PM_BR_PRED_CCACHE");
147         setup_event(&events[1], PM_BR_MPRED_CCACHE, "PM_BR_MPRED_CCACHE");
148         FAIL_IF(event_open(&events[0]));
149         FAIL_IF(event_open_with_group(&events[1], events[0].fd) == -1);
150 
151         is_p9 = ((mfspr(SPRN_PVR) >>  16) & 0xFFFF) == 0x4e;
152 
153         if (is_p9) {
154                 // Count pattern cache too
155                 setup_event(&events[2], PM_BR_PRED_PCACHE,  "PM_BR_PRED_PCACHE");
156                 setup_event(&events[3], PM_BR_MPRED_PCACHE, "PM_BR_MPRED_PCACHE");
157 
158                 FAIL_IF(event_open_with_group(&events[2], events[0].fd) == -1);
159                 FAIL_IF(event_open_with_group(&events[3], events[0].fd) == -1);
160         }
161 
162         FAIL_IF(do_count_loop(events, is_p9, &miss_percent));
163 
164         event_report_justified(&events[0], 18, 10);
165         event_report_justified(&events[1], 18, 10);
166         event_close(&events[0]);
167         event_close(&events[1]);
168 
169         if (is_p9) {
170                 event_report_justified(&events[2], 18, 10);
171                 event_report_justified(&events[3], 18, 10);
172                 event_close(&events[2]);
173                 event_close(&events[3]);
174         }
175 
176         printf("Miss percent %lld %%\n", miss_percent);
177 
178         switch (state) {
179         case VULNERABLE:
180         case NOT_AFFECTED:
181         case COUNT_CACHE_FLUSH_SW:
182         case COUNT_CACHE_FLUSH_HW:
183                 // These should all not affect userspace branch prediction
184                 if (miss_percent > 15) {
185                         if (miss_percent > 95) {
186                                 /*
187                                  * Such a mismatch may be caused by a system being unaware
188                                  * the count cache is disabled. This may be to enable
189                                  * guest migration between hosts with different settings.
190                                  * Return skip code to avoid detecting this as an error.
191                                  * We are not vulnerable and reporting otherwise, so
192                                  * missing such a mismatch is safe.
193                                  */
194                                 printf("Branch misses > 95%% unexpected in this configuration.\n");
195                                 printf("Count cache likely disabled without Linux knowing.\n");
196                                 if (state == COUNT_CACHE_FLUSH_SW)
197                                         printf("WARNING: Kernel performing unnecessary flushes.\n");
198                                 return 4;
199                         }
200                         printf("Branch misses > 15%% unexpected in this configuration!\n");
201                         printf("Possible mismatch between reported & actual mitigation\n");
202 
203                         return 1;
204                 }
205                 break;
206         case BRANCH_SERIALISATION:
207                 // This seems to affect userspace branch prediction a bit?
208                 if (miss_percent > 25) {
209                         printf("Branch misses > 25%% unexpected in this configuration!\n");
210                         printf("Possible mismatch between reported & actual mitigation\n");
211                         return 1;
212                 }
213                 break;
214         case COUNT_CACHE_DISABLED:
215                 if (miss_percent < 95) {
216                         printf("Branch misses < 95%% unexpected in this configuration!\n");
217                         printf("Possible mismatch between reported & actual mitigation\n");
218                         return 1;
219                 }
220                 break;
221         case UNKNOWN:
222         case BTB_FLUSH:
223                 printf("Not sure!\n");
224                 return 1;
225         }
226 
227         printf("OK - Measured branch prediction rates match reported spectre v2 mitigation.\n");
228 
229         return 0;
230 }
231 
232 int main(int argc, char *argv[])
233 {
234         return test_harness(spectre_v2_test, "spectre_v2");
235 }
236 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php