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