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