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 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 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 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 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 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