1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdbool.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/utsname.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <zlib.h>
13
14 #include "unpriv_helpers.h"
15
open_config(void)16 static gzFile open_config(void)
17 {
18 struct utsname uts;
19 char buf[PATH_MAX];
20 gzFile config;
21
22 if (uname(&uts)) {
23 perror("uname");
24 goto config_gz;
25 }
26
27 snprintf(buf, sizeof(buf), "/boot/config-%s", uts.release);
28 config = gzopen(buf, "rb");
29 if (config)
30 return config;
31 fprintf(stderr, "gzopen %s: %s\n", buf, strerror(errno));
32
33 config_gz:
34 config = gzopen("/proc/config.gz", "rb");
35 if (!config)
36 perror("gzopen /proc/config.gz");
37 return config;
38 }
39
config_contains(const char * pat)40 static int config_contains(const char *pat)
41 {
42 const char *msg;
43 char buf[1024];
44 gzFile config;
45 int n, err;
46
47 config = open_config();
48 if (!config)
49 return -1;
50
51 for (;;) {
52 if (!gzgets(config, buf, sizeof(buf))) {
53 msg = gzerror(config, &err);
54 if (err == Z_ERRNO)
55 perror("gzgets /proc/config.gz");
56 else if (err != Z_OK)
57 fprintf(stderr, "gzgets /proc/config.gz: %s", msg);
58 gzclose(config);
59 return -1;
60 }
61 n = strlen(buf);
62 if (buf[n - 1] == '\n')
63 buf[n - 1] = 0;
64 if (strcmp(buf, pat) == 0) {
65 gzclose(config);
66 return 1;
67 }
68 }
69 gzclose(config);
70 return 0;
71 }
72
cmdline_contains(const char * pat)73 static bool cmdline_contains(const char *pat)
74 {
75 char cmdline[4096], *c;
76 int fd, ret = false;
77
78 fd = open("/proc/cmdline", O_RDONLY);
79 if (fd < 0) {
80 perror("open /proc/cmdline");
81 return false;
82 }
83
84 if (read(fd, cmdline, sizeof(cmdline) - 1) < 0) {
85 perror("read /proc/cmdline");
86 goto out;
87 }
88
89 cmdline[sizeof(cmdline) - 1] = '\0';
90 for (c = strtok(cmdline, " \n"); c; c = strtok(NULL, " \n")) {
91 if (strncmp(c, pat, strlen(c)))
92 continue;
93 ret = true;
94 break;
95 }
96 out:
97 close(fd);
98 return ret;
99 }
100
get_mitigations_off(void)101 static int get_mitigations_off(void)
102 {
103 int enabled_in_config;
104
105 if (cmdline_contains("mitigations=off"))
106 return 1;
107 enabled_in_config = config_contains("CONFIG_CPU_MITIGATIONS=y");
108 if (enabled_in_config < 0)
109 return -1;
110 return !enabled_in_config;
111 }
112
get_unpriv_disabled(void)113 bool get_unpriv_disabled(void)
114 {
115 int mitigations_off;
116 bool disabled;
117 char buf[2];
118 FILE *fd;
119
120 fd = fopen("/proc/sys/" UNPRIV_SYSCTL, "r");
121 if (fd) {
122 disabled = (fgets(buf, 2, fd) == buf && atoi(buf));
123 fclose(fd);
124 } else {
125 perror("fopen /proc/sys/" UNPRIV_SYSCTL);
126 disabled = true;
127 }
128
129 if (disabled)
130 return true;
131
132 /*
133 * Some unpriv tests rely on spectre mitigations being on.
134 * If mitigations are off or status can't be determined
135 * assume that unpriv tests are disabled.
136 */
137 mitigations_off = get_mitigations_off();
138 if (mitigations_off < 0) {
139 fprintf(stderr,
140 "Can't determine if mitigations are enabled, disabling unpriv tests.");
141 return true;
142 }
143 return mitigations_off;
144 }
145