xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/wireguard/qemu/init.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #define _GNU_SOURCE
7*4882a593Smuzhiyun #include <unistd.h>
8*4882a593Smuzhiyun #include <errno.h>
9*4882a593Smuzhiyun #include <string.h>
10*4882a593Smuzhiyun #include <stdio.h>
11*4882a593Smuzhiyun #include <stdlib.h>
12*4882a593Smuzhiyun #include <stdbool.h>
13*4882a593Smuzhiyun #include <fcntl.h>
14*4882a593Smuzhiyun #include <sys/wait.h>
15*4882a593Smuzhiyun #include <sys/mount.h>
16*4882a593Smuzhiyun #include <sys/stat.h>
17*4882a593Smuzhiyun #include <sys/types.h>
18*4882a593Smuzhiyun #include <sys/io.h>
19*4882a593Smuzhiyun #include <sys/ioctl.h>
20*4882a593Smuzhiyun #include <sys/reboot.h>
21*4882a593Smuzhiyun #include <sys/utsname.h>
22*4882a593Smuzhiyun #include <sys/sendfile.h>
23*4882a593Smuzhiyun #include <sys/sysmacros.h>
24*4882a593Smuzhiyun #include <linux/random.h>
25*4882a593Smuzhiyun #include <linux/version.h>
26*4882a593Smuzhiyun 
poweroff(void)27*4882a593Smuzhiyun __attribute__((noreturn)) static void poweroff(void)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	fflush(stdout);
30*4882a593Smuzhiyun 	fflush(stderr);
31*4882a593Smuzhiyun 	reboot(RB_AUTOBOOT);
32*4882a593Smuzhiyun 	sleep(30);
33*4882a593Smuzhiyun 	fprintf(stderr, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n");
34*4882a593Smuzhiyun 	exit(1);
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
panic(const char * what)37*4882a593Smuzhiyun static void panic(const char *what)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	fprintf(stderr, "\n\n\x1b[37m\x1b[41m\x1b[1mSOMETHING WENT HORRIBLY WRONG\x1b[0m\n\n    \x1b[31m\x1b[1m%s: %s\x1b[0m\n\n\x1b[37m\x1b[44m\x1b[1mPower off...\x1b[0m\n\n", what, strerror(errno));
40*4882a593Smuzhiyun 	poweroff();
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m")
44*4882a593Smuzhiyun 
print_banner(void)45*4882a593Smuzhiyun static void print_banner(void)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct utsname utsname;
48*4882a593Smuzhiyun 	int len;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	if (uname(&utsname) < 0)
51*4882a593Smuzhiyun 		panic("uname");
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	len = strlen("    WireGuard Test Suite on       ") + strlen(utsname.sysname) + strlen(utsname.release) + strlen(utsname.machine);
54*4882a593Smuzhiyun 	printf("\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\x1b[45m\x1b[33m\x1b[1m    WireGuard Test Suite on %s %s %s    \x1b[0m\n\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\n", len, "", utsname.sysname, utsname.release, utsname.machine, len, "");
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
seed_rng(void)57*4882a593Smuzhiyun static void seed_rng(void)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	int fd;
60*4882a593Smuzhiyun 	struct {
61*4882a593Smuzhiyun 		int entropy_count;
62*4882a593Smuzhiyun 		int buffer_size;
63*4882a593Smuzhiyun 		unsigned char buffer[256];
64*4882a593Smuzhiyun 	} entropy = {
65*4882a593Smuzhiyun 		.entropy_count = sizeof(entropy.buffer) * 8,
66*4882a593Smuzhiyun 		.buffer_size = sizeof(entropy.buffer),
67*4882a593Smuzhiyun 		.buffer = "Adding real entropy is not actually important for these tests. Don't try this at home, kids!"
68*4882a593Smuzhiyun 	};
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	if (mknod("/dev/urandom", S_IFCHR | 0644, makedev(1, 9)))
71*4882a593Smuzhiyun 		panic("mknod(/dev/urandom)");
72*4882a593Smuzhiyun 	fd = open("/dev/urandom", O_WRONLY);
73*4882a593Smuzhiyun 	if (fd < 0)
74*4882a593Smuzhiyun 		panic("open(urandom)");
75*4882a593Smuzhiyun 	for (int i = 0; i < 256; ++i) {
76*4882a593Smuzhiyun 		if (ioctl(fd, RNDADDENTROPY, &entropy) < 0)
77*4882a593Smuzhiyun 			panic("ioctl(urandom)");
78*4882a593Smuzhiyun 	}
79*4882a593Smuzhiyun 	close(fd);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
mount_filesystems(void)82*4882a593Smuzhiyun static void mount_filesystems(void)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	pretty_message("[+] Mounting filesystems...");
85*4882a593Smuzhiyun 	mkdir("/dev", 0755);
86*4882a593Smuzhiyun 	mkdir("/proc", 0755);
87*4882a593Smuzhiyun 	mkdir("/sys", 0755);
88*4882a593Smuzhiyun 	mkdir("/tmp", 0755);
89*4882a593Smuzhiyun 	mkdir("/run", 0755);
90*4882a593Smuzhiyun 	mkdir("/var", 0755);
91*4882a593Smuzhiyun 	if (mount("none", "/dev", "devtmpfs", 0, NULL))
92*4882a593Smuzhiyun 		panic("devtmpfs mount");
93*4882a593Smuzhiyun 	if (mount("none", "/proc", "proc", 0, NULL))
94*4882a593Smuzhiyun 		panic("procfs mount");
95*4882a593Smuzhiyun 	if (mount("none", "/sys", "sysfs", 0, NULL))
96*4882a593Smuzhiyun 		panic("sysfs mount");
97*4882a593Smuzhiyun 	if (mount("none", "/tmp", "tmpfs", 0, NULL))
98*4882a593Smuzhiyun 		panic("tmpfs mount");
99*4882a593Smuzhiyun 	if (mount("none", "/run", "tmpfs", 0, NULL))
100*4882a593Smuzhiyun 		panic("tmpfs mount");
101*4882a593Smuzhiyun 	if (mount("none", "/sys/kernel/debug", "debugfs", 0, NULL))
102*4882a593Smuzhiyun 		; /* Not a problem if it fails.*/
103*4882a593Smuzhiyun 	if (symlink("/run", "/var/run"))
104*4882a593Smuzhiyun 		panic("run symlink");
105*4882a593Smuzhiyun 	if (symlink("/proc/self/fd", "/dev/fd"))
106*4882a593Smuzhiyun 		panic("fd symlink");
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
enable_logging(void)109*4882a593Smuzhiyun static void enable_logging(void)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	int fd;
112*4882a593Smuzhiyun 	pretty_message("[+] Enabling logging...");
113*4882a593Smuzhiyun 	fd = open("/proc/sys/kernel/printk", O_WRONLY);
114*4882a593Smuzhiyun 	if (fd >= 0) {
115*4882a593Smuzhiyun 		if (write(fd, "9\n", 2) != 2)
116*4882a593Smuzhiyun 			panic("write(printk)");
117*4882a593Smuzhiyun 		close(fd);
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 	fd = open("/proc/sys/debug/exception-trace", O_WRONLY);
120*4882a593Smuzhiyun 	if (fd >= 0) {
121*4882a593Smuzhiyun 		if (write(fd, "1\n", 2) != 2)
122*4882a593Smuzhiyun 			panic("write(exception-trace)");
123*4882a593Smuzhiyun 		close(fd);
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	fd = open("/proc/sys/kernel/panic_on_warn", O_WRONLY);
126*4882a593Smuzhiyun 	if (fd >= 0) {
127*4882a593Smuzhiyun 		if (write(fd, "1\n", 2) != 2)
128*4882a593Smuzhiyun 			panic("write(panic_on_warn)");
129*4882a593Smuzhiyun 		close(fd);
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
kmod_selftests(void)133*4882a593Smuzhiyun static void kmod_selftests(void)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	FILE *file;
136*4882a593Smuzhiyun 	char line[2048], *start, *pass;
137*4882a593Smuzhiyun 	bool success = true;
138*4882a593Smuzhiyun 	pretty_message("[+] Module self-tests:");
139*4882a593Smuzhiyun 	file = fopen("/proc/kmsg", "r");
140*4882a593Smuzhiyun 	if (!file)
141*4882a593Smuzhiyun 		panic("fopen(kmsg)");
142*4882a593Smuzhiyun 	if (fcntl(fileno(file), F_SETFL, O_NONBLOCK) < 0)
143*4882a593Smuzhiyun 		panic("fcntl(kmsg, nonblock)");
144*4882a593Smuzhiyun 	while (fgets(line, sizeof(line), file)) {
145*4882a593Smuzhiyun 		start = strstr(line, "wireguard: ");
146*4882a593Smuzhiyun 		if (!start)
147*4882a593Smuzhiyun 			continue;
148*4882a593Smuzhiyun 		start += 11;
149*4882a593Smuzhiyun 		*strchrnul(start, '\n') = '\0';
150*4882a593Smuzhiyun 		if (strstr(start, "www.wireguard.com"))
151*4882a593Smuzhiyun 			break;
152*4882a593Smuzhiyun 		pass = strstr(start, ": pass");
153*4882a593Smuzhiyun 		if (!pass || pass[6] != '\0') {
154*4882a593Smuzhiyun 			success = false;
155*4882a593Smuzhiyun 			printf(" \x1b[31m*  %s\x1b[0m\n", start);
156*4882a593Smuzhiyun 		} else
157*4882a593Smuzhiyun 			printf(" \x1b[32m*  %s\x1b[0m\n", start);
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 	fclose(file);
160*4882a593Smuzhiyun 	if (!success) {
161*4882a593Smuzhiyun 		puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m");
162*4882a593Smuzhiyun 		poweroff();
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
launch_tests(void)166*4882a593Smuzhiyun static void launch_tests(void)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	char cmdline[4096], *success_dev;
169*4882a593Smuzhiyun 	int status, fd;
170*4882a593Smuzhiyun 	pid_t pid;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	pretty_message("[+] Launching tests...");
173*4882a593Smuzhiyun 	pid = fork();
174*4882a593Smuzhiyun 	if (pid == -1)
175*4882a593Smuzhiyun 		panic("fork");
176*4882a593Smuzhiyun 	else if (pid == 0) {
177*4882a593Smuzhiyun 		execl("/init.sh", "init", NULL);
178*4882a593Smuzhiyun 		panic("exec");
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 	if (waitpid(pid, &status, 0) < 0)
181*4882a593Smuzhiyun 		panic("waitpid");
182*4882a593Smuzhiyun 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
183*4882a593Smuzhiyun 		pretty_message("[+] Tests successful! :-)");
184*4882a593Smuzhiyun 		fd = open("/proc/cmdline", O_RDONLY);
185*4882a593Smuzhiyun 		if (fd < 0)
186*4882a593Smuzhiyun 			panic("open(/proc/cmdline)");
187*4882a593Smuzhiyun 		if (read(fd, cmdline, sizeof(cmdline) - 1) <= 0)
188*4882a593Smuzhiyun 			panic("read(/proc/cmdline)");
189*4882a593Smuzhiyun 		cmdline[sizeof(cmdline) - 1] = '\0';
190*4882a593Smuzhiyun 		for (success_dev = strtok(cmdline, " \n"); success_dev; success_dev = strtok(NULL, " \n")) {
191*4882a593Smuzhiyun 			if (strncmp(success_dev, "wg.success=", 11))
192*4882a593Smuzhiyun 				continue;
193*4882a593Smuzhiyun 			memcpy(success_dev + 11 - 5, "/dev/", 5);
194*4882a593Smuzhiyun 			success_dev += 11 - 5;
195*4882a593Smuzhiyun 			break;
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 		if (!success_dev || !strlen(success_dev))
198*4882a593Smuzhiyun 			panic("Unable to find success device");
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 		fd = open(success_dev, O_WRONLY);
201*4882a593Smuzhiyun 		if (fd < 0)
202*4882a593Smuzhiyun 			panic("open(success_dev)");
203*4882a593Smuzhiyun 		if (write(fd, "success\n", 8) != 8)
204*4882a593Smuzhiyun 			panic("write(success_dev)");
205*4882a593Smuzhiyun 		close(fd);
206*4882a593Smuzhiyun 	} else {
207*4882a593Smuzhiyun 		const char *why = "unknown cause";
208*4882a593Smuzhiyun 		int what = -1;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 		if (WIFEXITED(status)) {
211*4882a593Smuzhiyun 			why = "exit code";
212*4882a593Smuzhiyun 			what = WEXITSTATUS(status);
213*4882a593Smuzhiyun 		} else if (WIFSIGNALED(status)) {
214*4882a593Smuzhiyun 			why = "signal";
215*4882a593Smuzhiyun 			what = WTERMSIG(status);
216*4882a593Smuzhiyun 		}
217*4882a593Smuzhiyun 		printf("\x1b[31m\x1b[1m[-] Tests failed with %s %d! \u2639\x1b[0m\n", why, what);
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
ensure_console(void)221*4882a593Smuzhiyun static void ensure_console(void)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	for (unsigned int i = 0; i < 1000; ++i) {
224*4882a593Smuzhiyun 		int fd = open("/dev/console", O_RDWR);
225*4882a593Smuzhiyun 		if (fd < 0) {
226*4882a593Smuzhiyun 			usleep(50000);
227*4882a593Smuzhiyun 			continue;
228*4882a593Smuzhiyun 		}
229*4882a593Smuzhiyun 		dup2(fd, 0);
230*4882a593Smuzhiyun 		dup2(fd, 1);
231*4882a593Smuzhiyun 		dup2(fd, 2);
232*4882a593Smuzhiyun 		close(fd);
233*4882a593Smuzhiyun 		if (write(1, "\0\0\0\0\n", 5) == 5)
234*4882a593Smuzhiyun 			return;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 	panic("Unable to open console device");
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
clear_leaks(void)239*4882a593Smuzhiyun static void clear_leaks(void)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	int fd;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	fd = open("/sys/kernel/debug/kmemleak", O_WRONLY);
244*4882a593Smuzhiyun 	if (fd < 0)
245*4882a593Smuzhiyun 		return;
246*4882a593Smuzhiyun 	pretty_message("[+] Starting memory leak detection...");
247*4882a593Smuzhiyun 	write(fd, "clear\n", 5);
248*4882a593Smuzhiyun 	close(fd);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
check_leaks(void)251*4882a593Smuzhiyun static void check_leaks(void)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	int fd;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	fd = open("/sys/kernel/debug/kmemleak", O_WRONLY);
256*4882a593Smuzhiyun 	if (fd < 0)
257*4882a593Smuzhiyun 		return;
258*4882a593Smuzhiyun 	pretty_message("[+] Scanning for memory leaks...");
259*4882a593Smuzhiyun 	sleep(2); /* Wait for any grace periods. */
260*4882a593Smuzhiyun 	write(fd, "scan\n", 5);
261*4882a593Smuzhiyun 	close(fd);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	fd = open("/sys/kernel/debug/kmemleak", O_RDONLY);
264*4882a593Smuzhiyun 	if (fd < 0)
265*4882a593Smuzhiyun 		return;
266*4882a593Smuzhiyun 	if (sendfile(1, fd, NULL, 0x7ffff000) > 0)
267*4882a593Smuzhiyun 		panic("Memory leaks encountered");
268*4882a593Smuzhiyun 	close(fd);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
main(int argc,char * argv[])271*4882a593Smuzhiyun int main(int argc, char *argv[])
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	seed_rng();
274*4882a593Smuzhiyun 	ensure_console();
275*4882a593Smuzhiyun 	print_banner();
276*4882a593Smuzhiyun 	mount_filesystems();
277*4882a593Smuzhiyun 	kmod_selftests();
278*4882a593Smuzhiyun 	enable_logging();
279*4882a593Smuzhiyun 	clear_leaks();
280*4882a593Smuzhiyun 	launch_tests();
281*4882a593Smuzhiyun 	check_leaks();
282*4882a593Smuzhiyun 	poweroff();
283*4882a593Smuzhiyun 	return 1;
284*4882a593Smuzhiyun }
285