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>
17 #include <sys/types.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)
33 fprintf(stderr
, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n");
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
));
43 #define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m")
45 static void print_banner(void)
47 struct utsname utsname
;
50 if (uname(&utsname
) < 0)
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)
63 unsigned char buffer
[256];
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
);
74 panic("open(urandom)");
75 for (int i
= 0; i
< 256; ++i
) {
76 if (ioctl(fd
, RNDADDENTROPY
, &entropy
) < 0)
77 panic("ioctl(urandom)");
82 static void mount_filesystems(void)
84 pretty_message("[+] Mounting filesystems...");
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
))
97 if (mount("none", "/tmp", "tmpfs", 0, NULL
))
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"))
109 static void enable_logging(void)
112 pretty_message("[+] Enabling logging...");
113 fd
= open("/proc/sys/kernel/printk", O_WRONLY
);
115 if (write(fd
, "9\n", 2) != 2)
116 panic("write(printk)");
119 fd
= open("/proc/sys/debug/exception-trace", O_WRONLY
);
121 if (write(fd
, "1\n", 2) != 2)
122 panic("write(exception-trace)");
125 fd
= open("/proc/sys/kernel/panic_on_warn", O_WRONLY
);
127 if (write(fd
, "1\n", 2) != 2)
128 panic("write(panic_on_warn)");
133 static void kmod_selftests(void)
136 char line
[2048], *start
, *pass
;
138 pretty_message("[+] Module self-tests:");
139 file
= fopen("/proc/kmsg", "r");
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: ");
149 *strchrnul(start
, '\n') = '\0';
150 if (strstr(start
, "www.wireguard.com"))
152 pass
= strstr(start
, ": pass");
153 if (!pass
|| pass
[6] != '\0') {
155 printf(" \x1b[31m* %s\x1b[0m\n", start
);
157 printf(" \x1b[32m* %s\x1b[0m\n", start
);
161 puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m");
166 static void launch_tests(void)
168 char cmdline
[4096], *success_dev
;
172 pretty_message("[+] Launching tests...");
177 execl("/init.sh", "init", NULL
);
180 if (waitpid(pid
, &status
, 0) < 0)
182 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 0) {
183 pretty_message("[+] Tests successful! :-)");
184 fd
= open("/proc/cmdline", O_RDONLY
);
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))
193 memcpy(success_dev
+ 11 - 5, "/dev/", 5);
194 success_dev
+= 11 - 5;
197 if (!success_dev
|| !strlen(success_dev
))
198 panic("Unable to find success device");
200 fd
= open(success_dev
, O_WRONLY
);
202 panic("open(success_dev)");
203 if (write(fd
, "success\n", 8) != 8)
204 panic("write(success_dev)");
207 const char *why
= "unknown cause";
210 if (WIFEXITED(status
)) {
212 what
= WEXITSTATUS(status
);
213 } else if (WIFSIGNALED(status
)) {
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
);
233 if (write(1, "\0\0\0\0\n", 5) == 5)
236 panic("Unable to open console device");
239 static void clear_leaks(void)
243 fd
= open("/sys/kernel/debug/kmemleak", O_WRONLY
);
246 pretty_message("[+] Starting memory leak detection...");
247 write(fd
, "clear\n", 5);
251 static void check_leaks(void)
255 fd
= open("/sys/kernel/debug/kmemleak", O_WRONLY
);
258 pretty_message("[+] Scanning for memory leaks...");
259 sleep(2); /* Wait for any grace periods. */
260 write(fd
, "scan\n", 5);
263 fd
= open("/sys/kernel/debug/kmemleak", O_RDONLY
);
266 if (sendfile(1, fd
, NULL
, 0x7ffff000) > 0)
267 panic("Memory leaks encountered");
271 int main(int argc
, char *argv
[])