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