18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define _GNU_SOURCE 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <stdio.h> 118c2ecf20Sopenharmony_ci#include <stdlib.h> 128c2ecf20Sopenharmony_ci#include <stdbool.h> 138c2ecf20Sopenharmony_ci#include <fcntl.h> 148c2ecf20Sopenharmony_ci#include <sys/wait.h> 158c2ecf20Sopenharmony_ci#include <sys/mount.h> 168c2ecf20Sopenharmony_ci#include <sys/stat.h> 178c2ecf20Sopenharmony_ci#include <sys/types.h> 188c2ecf20Sopenharmony_ci#include <sys/io.h> 198c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 208c2ecf20Sopenharmony_ci#include <sys/reboot.h> 218c2ecf20Sopenharmony_ci#include <sys/utsname.h> 228c2ecf20Sopenharmony_ci#include <sys/sendfile.h> 238c2ecf20Sopenharmony_ci#include <sys/sysmacros.h> 248c2ecf20Sopenharmony_ci#include <linux/random.h> 258c2ecf20Sopenharmony_ci#include <linux/version.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci__attribute__((noreturn)) static void poweroff(void) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci fflush(stdout); 308c2ecf20Sopenharmony_ci fflush(stderr); 318c2ecf20Sopenharmony_ci reboot(RB_AUTOBOOT); 328c2ecf20Sopenharmony_ci sleep(30); 338c2ecf20Sopenharmony_ci fprintf(stderr, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n"); 348c2ecf20Sopenharmony_ci exit(1); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void panic(const char *what) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci 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)); 408c2ecf20Sopenharmony_ci poweroff(); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m") 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void print_banner(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct utsname utsname; 488c2ecf20Sopenharmony_ci int len; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (uname(&utsname) < 0) 518c2ecf20Sopenharmony_ci panic("uname"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci len = strlen(" WireGuard Test Suite on ") + strlen(utsname.sysname) + strlen(utsname.release) + strlen(utsname.machine); 548c2ecf20Sopenharmony_ci 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, ""); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void seed_rng(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int fd; 608c2ecf20Sopenharmony_ci struct { 618c2ecf20Sopenharmony_ci int entropy_count; 628c2ecf20Sopenharmony_ci int buffer_size; 638c2ecf20Sopenharmony_ci unsigned char buffer[256]; 648c2ecf20Sopenharmony_ci } entropy = { 658c2ecf20Sopenharmony_ci .entropy_count = sizeof(entropy.buffer) * 8, 668c2ecf20Sopenharmony_ci .buffer_size = sizeof(entropy.buffer), 678c2ecf20Sopenharmony_ci .buffer = "Adding real entropy is not actually important for these tests. Don't try this at home, kids!" 688c2ecf20Sopenharmony_ci }; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (mknod("/dev/urandom", S_IFCHR | 0644, makedev(1, 9))) 718c2ecf20Sopenharmony_ci panic("mknod(/dev/urandom)"); 728c2ecf20Sopenharmony_ci fd = open("/dev/urandom", O_WRONLY); 738c2ecf20Sopenharmony_ci if (fd < 0) 748c2ecf20Sopenharmony_ci panic("open(urandom)"); 758c2ecf20Sopenharmony_ci for (int i = 0; i < 256; ++i) { 768c2ecf20Sopenharmony_ci if (ioctl(fd, RNDADDENTROPY, &entropy) < 0) 778c2ecf20Sopenharmony_ci panic("ioctl(urandom)"); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci close(fd); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void mount_filesystems(void) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci pretty_message("[+] Mounting filesystems..."); 858c2ecf20Sopenharmony_ci mkdir("/dev", 0755); 868c2ecf20Sopenharmony_ci mkdir("/proc", 0755); 878c2ecf20Sopenharmony_ci mkdir("/sys", 0755); 888c2ecf20Sopenharmony_ci mkdir("/tmp", 0755); 898c2ecf20Sopenharmony_ci mkdir("/run", 0755); 908c2ecf20Sopenharmony_ci mkdir("/var", 0755); 918c2ecf20Sopenharmony_ci if (mount("none", "/dev", "devtmpfs", 0, NULL)) 928c2ecf20Sopenharmony_ci panic("devtmpfs mount"); 938c2ecf20Sopenharmony_ci if (mount("none", "/proc", "proc", 0, NULL)) 948c2ecf20Sopenharmony_ci panic("procfs mount"); 958c2ecf20Sopenharmony_ci if (mount("none", "/sys", "sysfs", 0, NULL)) 968c2ecf20Sopenharmony_ci panic("sysfs mount"); 978c2ecf20Sopenharmony_ci if (mount("none", "/tmp", "tmpfs", 0, NULL)) 988c2ecf20Sopenharmony_ci panic("tmpfs mount"); 998c2ecf20Sopenharmony_ci if (mount("none", "/run", "tmpfs", 0, NULL)) 1008c2ecf20Sopenharmony_ci panic("tmpfs mount"); 1018c2ecf20Sopenharmony_ci if (mount("none", "/sys/kernel/debug", "debugfs", 0, NULL)) 1028c2ecf20Sopenharmony_ci ; /* Not a problem if it fails.*/ 1038c2ecf20Sopenharmony_ci if (symlink("/run", "/var/run")) 1048c2ecf20Sopenharmony_ci panic("run symlink"); 1058c2ecf20Sopenharmony_ci if (symlink("/proc/self/fd", "/dev/fd")) 1068c2ecf20Sopenharmony_ci panic("fd symlink"); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void enable_logging(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int fd; 1128c2ecf20Sopenharmony_ci pretty_message("[+] Enabling logging..."); 1138c2ecf20Sopenharmony_ci fd = open("/proc/sys/kernel/printk", O_WRONLY); 1148c2ecf20Sopenharmony_ci if (fd >= 0) { 1158c2ecf20Sopenharmony_ci if (write(fd, "9\n", 2) != 2) 1168c2ecf20Sopenharmony_ci panic("write(printk)"); 1178c2ecf20Sopenharmony_ci close(fd); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci fd = open("/proc/sys/debug/exception-trace", O_WRONLY); 1208c2ecf20Sopenharmony_ci if (fd >= 0) { 1218c2ecf20Sopenharmony_ci if (write(fd, "1\n", 2) != 2) 1228c2ecf20Sopenharmony_ci panic("write(exception-trace)"); 1238c2ecf20Sopenharmony_ci close(fd); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci fd = open("/proc/sys/kernel/panic_on_warn", O_WRONLY); 1268c2ecf20Sopenharmony_ci if (fd >= 0) { 1278c2ecf20Sopenharmony_ci if (write(fd, "1\n", 2) != 2) 1288c2ecf20Sopenharmony_ci panic("write(panic_on_warn)"); 1298c2ecf20Sopenharmony_ci close(fd); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void kmod_selftests(void) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci FILE *file; 1368c2ecf20Sopenharmony_ci char line[2048], *start, *pass; 1378c2ecf20Sopenharmony_ci bool success = true; 1388c2ecf20Sopenharmony_ci pretty_message("[+] Module self-tests:"); 1398c2ecf20Sopenharmony_ci file = fopen("/proc/kmsg", "r"); 1408c2ecf20Sopenharmony_ci if (!file) 1418c2ecf20Sopenharmony_ci panic("fopen(kmsg)"); 1428c2ecf20Sopenharmony_ci if (fcntl(fileno(file), F_SETFL, O_NONBLOCK) < 0) 1438c2ecf20Sopenharmony_ci panic("fcntl(kmsg, nonblock)"); 1448c2ecf20Sopenharmony_ci while (fgets(line, sizeof(line), file)) { 1458c2ecf20Sopenharmony_ci start = strstr(line, "wireguard: "); 1468c2ecf20Sopenharmony_ci if (!start) 1478c2ecf20Sopenharmony_ci continue; 1488c2ecf20Sopenharmony_ci start += 11; 1498c2ecf20Sopenharmony_ci *strchrnul(start, '\n') = '\0'; 1508c2ecf20Sopenharmony_ci if (strstr(start, "www.wireguard.com")) 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci pass = strstr(start, ": pass"); 1538c2ecf20Sopenharmony_ci if (!pass || pass[6] != '\0') { 1548c2ecf20Sopenharmony_ci success = false; 1558c2ecf20Sopenharmony_ci printf(" \x1b[31m* %s\x1b[0m\n", start); 1568c2ecf20Sopenharmony_ci } else 1578c2ecf20Sopenharmony_ci printf(" \x1b[32m* %s\x1b[0m\n", start); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci fclose(file); 1608c2ecf20Sopenharmony_ci if (!success) { 1618c2ecf20Sopenharmony_ci puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m"); 1628c2ecf20Sopenharmony_ci poweroff(); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void launch_tests(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci char cmdline[4096], *success_dev; 1698c2ecf20Sopenharmony_ci int status, fd; 1708c2ecf20Sopenharmony_ci pid_t pid; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci pretty_message("[+] Launching tests..."); 1738c2ecf20Sopenharmony_ci pid = fork(); 1748c2ecf20Sopenharmony_ci if (pid == -1) 1758c2ecf20Sopenharmony_ci panic("fork"); 1768c2ecf20Sopenharmony_ci else if (pid == 0) { 1778c2ecf20Sopenharmony_ci execl("/init.sh", "init", NULL); 1788c2ecf20Sopenharmony_ci panic("exec"); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci if (waitpid(pid, &status, 0) < 0) 1818c2ecf20Sopenharmony_ci panic("waitpid"); 1828c2ecf20Sopenharmony_ci if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 1838c2ecf20Sopenharmony_ci pretty_message("[+] Tests successful! :-)"); 1848c2ecf20Sopenharmony_ci fd = open("/proc/cmdline", O_RDONLY); 1858c2ecf20Sopenharmony_ci if (fd < 0) 1868c2ecf20Sopenharmony_ci panic("open(/proc/cmdline)"); 1878c2ecf20Sopenharmony_ci if (read(fd, cmdline, sizeof(cmdline) - 1) <= 0) 1888c2ecf20Sopenharmony_ci panic("read(/proc/cmdline)"); 1898c2ecf20Sopenharmony_ci cmdline[sizeof(cmdline) - 1] = '\0'; 1908c2ecf20Sopenharmony_ci for (success_dev = strtok(cmdline, " \n"); success_dev; success_dev = strtok(NULL, " \n")) { 1918c2ecf20Sopenharmony_ci if (strncmp(success_dev, "wg.success=", 11)) 1928c2ecf20Sopenharmony_ci continue; 1938c2ecf20Sopenharmony_ci memcpy(success_dev + 11 - 5, "/dev/", 5); 1948c2ecf20Sopenharmony_ci success_dev += 11 - 5; 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci if (!success_dev || !strlen(success_dev)) 1988c2ecf20Sopenharmony_ci panic("Unable to find success device"); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci fd = open(success_dev, O_WRONLY); 2018c2ecf20Sopenharmony_ci if (fd < 0) 2028c2ecf20Sopenharmony_ci panic("open(success_dev)"); 2038c2ecf20Sopenharmony_ci if (write(fd, "success\n", 8) != 8) 2048c2ecf20Sopenharmony_ci panic("write(success_dev)"); 2058c2ecf20Sopenharmony_ci close(fd); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci const char *why = "unknown cause"; 2088c2ecf20Sopenharmony_ci int what = -1; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (WIFEXITED(status)) { 2118c2ecf20Sopenharmony_ci why = "exit code"; 2128c2ecf20Sopenharmony_ci what = WEXITSTATUS(status); 2138c2ecf20Sopenharmony_ci } else if (WIFSIGNALED(status)) { 2148c2ecf20Sopenharmony_ci why = "signal"; 2158c2ecf20Sopenharmony_ci what = WTERMSIG(status); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci printf("\x1b[31m\x1b[1m[-] Tests failed with %s %d! \u2639\x1b[0m\n", why, what); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void ensure_console(void) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci for (unsigned int i = 0; i < 1000; ++i) { 2248c2ecf20Sopenharmony_ci int fd = open("/dev/console", O_RDWR); 2258c2ecf20Sopenharmony_ci if (fd < 0) { 2268c2ecf20Sopenharmony_ci usleep(50000); 2278c2ecf20Sopenharmony_ci continue; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci dup2(fd, 0); 2308c2ecf20Sopenharmony_ci dup2(fd, 1); 2318c2ecf20Sopenharmony_ci dup2(fd, 2); 2328c2ecf20Sopenharmony_ci close(fd); 2338c2ecf20Sopenharmony_ci if (write(1, "\0\0\0\0\n", 5) == 5) 2348c2ecf20Sopenharmony_ci return; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci panic("Unable to open console device"); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void clear_leaks(void) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int fd; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci fd = open("/sys/kernel/debug/kmemleak", O_WRONLY); 2448c2ecf20Sopenharmony_ci if (fd < 0) 2458c2ecf20Sopenharmony_ci return; 2468c2ecf20Sopenharmony_ci pretty_message("[+] Starting memory leak detection..."); 2478c2ecf20Sopenharmony_ci write(fd, "clear\n", 5); 2488c2ecf20Sopenharmony_ci close(fd); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void check_leaks(void) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci int fd; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci fd = open("/sys/kernel/debug/kmemleak", O_WRONLY); 2568c2ecf20Sopenharmony_ci if (fd < 0) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci pretty_message("[+] Scanning for memory leaks..."); 2598c2ecf20Sopenharmony_ci sleep(2); /* Wait for any grace periods. */ 2608c2ecf20Sopenharmony_ci write(fd, "scan\n", 5); 2618c2ecf20Sopenharmony_ci close(fd); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci fd = open("/sys/kernel/debug/kmemleak", O_RDONLY); 2648c2ecf20Sopenharmony_ci if (fd < 0) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci if (sendfile(1, fd, NULL, 0x7ffff000) > 0) 2678c2ecf20Sopenharmony_ci panic("Memory leaks encountered"); 2688c2ecf20Sopenharmony_ci close(fd); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci seed_rng(); 2748c2ecf20Sopenharmony_ci ensure_console(); 2758c2ecf20Sopenharmony_ci print_banner(); 2768c2ecf20Sopenharmony_ci mount_filesystems(); 2778c2ecf20Sopenharmony_ci kmod_selftests(); 2788c2ecf20Sopenharmony_ci enable_logging(); 2798c2ecf20Sopenharmony_ci clear_leaks(); 2808c2ecf20Sopenharmony_ci launch_tests(); 2818c2ecf20Sopenharmony_ci check_leaks(); 2828c2ecf20Sopenharmony_ci poweroff(); 2838c2ecf20Sopenharmony_ci return 1; 2848c2ecf20Sopenharmony_ci} 285