xref: /linux/tools/testing/selftests/bpf/unpriv_helpers.c (revision 0a91336e287ca2557fead5221d2c79e0effd034e)
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