1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
15 #include <sys/mount.h>
16 #include <sys/types.h>
18 #include <sys/types.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)
34 fprintf(stderr
, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n");
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
));
44 #define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m")
46 static void print_banner(void)
48 struct utsname utsname
;
51 if (uname(&utsname
) < 0)
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)
64 unsigned char buffer
[256];
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
);
75 panic("open(urandom)");
76 for (int i
= 0; i
< 256; ++i
) {
77 if (ioctl(fd
, RNDADDENTROPY
, &entropy
) < 0)
78 panic("ioctl(urandom)");
83 static void mount_filesystems(void)
85 pretty_message("[+] Mounting filesystems...");
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
))
98 if (mount("none", "/tmp", "tmpfs", 0, NULL
))
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"))
110 static void enable_logging(void)
113 pretty_message("[+] Enabling logging...");
114 fd
= open("/proc/sys/kernel/printk", O_WRONLY
);
116 if (write(fd
, "9\n", 2) != 2)
117 panic("write(printk)");
120 fd
= open("/proc/sys/debug/exception-trace", O_WRONLY
);
122 if (write(fd
, "1\n", 2) != 2)
123 panic("write(exception-trace)");
126 fd
= open("/proc/sys/kernel/panic_on_warn", O_WRONLY
);
128 if (write(fd
, "1\n", 2) != 2)
129 panic("write(panic_on_warn)");
134 static void kmod_selftests(void)
137 char line
[2048], *start
, *pass
;
139 pretty_message("[+] Module self-tests:");
140 file
= fopen("/proc/kmsg", "r");
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: ");
150 *strchrnul(start
, '\n') = '\0';
151 if (strstr(start
, "www.wireguard.com"))
153 pass
= strstr(start
, ": pass");
154 if (!pass
|| pass
[6] != '\0') {
156 printf(" \x1b[31m* %s\x1b[0m\n", start
);
158 printf(" \x1b[32m* %s\x1b[0m\n", start
);
162 puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m");
167 static void launch_tests(void)
169 char cmdline
[4096], *success_dev
;
173 pretty_message("[+] Launching tests...");
178 execl("/init.sh", "init", NULL
);
181 if (waitpid(pid
, &status
, 0) < 0)
183 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0) {
184 pretty_message("[+] Tests successful! :-)");
185 fd
= open("/proc/cmdline", O_RDONLY
);
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))
194 memcpy(success_dev
+ 11 - 5, "/dev/", 5);
195 success_dev
+= 11 - 5;
198 if (!success_dev
|| !strlen(success_dev
))
199 panic("Unable to find success device");
201 fd
= open(success_dev
, O_WRONLY
);
203 panic("open(success_dev)");
204 if (write(fd
, "success\n", 8) != 8)
205 panic("write(success_dev)");
208 const char *why
= "unknown cause";
211 if (WIFEXITED(status
)) {
213 what
= WEXITSTATUS(status
);
214 } else if (WIFSIGNALED(status
)) {
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
);
234 if (write(1, "\0\0\0\0\n", 5) == 5)
237 panic("Unable to open console device");
240 static void clear_leaks(void)
244 fd
= open("/sys/kernel/debug/kmemleak", O_WRONLY
);
247 pretty_message("[+] Starting memory leak detection...");
248 write(fd
, "clear\n", 5);
252 static void check_leaks(void)
256 fd
= open("/sys/kernel/debug/kmemleak", O_WRONLY
);
259 pretty_message("[+] Scanning for memory leaks...");
260 sleep(2); /* Wait for any grace periods. */
261 write(fd
, "scan\n", 5);
264 fd
= open("/sys/kernel/debug/kmemleak", O_RDONLY
);
267 if (sendfile(1, fd
, NULL
, 0x7ffff000) > 0)
268 panic("Memory leaks encountered");
272 int main(int argc
, char *argv
[])