linux/tools/testing/selftests/wireguard/qemu/init.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
   4 */
   5
   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>
  26
  27__attribute__((noreturn)) static void poweroff(void)
  28{
  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);
  35}
  36
  37static void panic(const char *what)
  38{
  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();
  41}
  42
  43#define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m")
  44
  45static void print_banner(void)
  46{
  47        struct utsname utsname;
  48        int len;
  49
  50        if (uname(&utsname) < 0)
  51                panic("uname");
  52
  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, "");
  55}
  56
  57static void seed_rng(void)
  58{
  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!"
  68        };
  69
  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)");
  78        }
  79        close(fd);
  80}
  81
  82static void mount_filesystems(void)
  83{
  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");
 107}
 108
 109static void enable_logging(void)
 110{
 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);
 118        }
 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);
 124        }
 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);
 130        }
 131}
 132
 133static void kmod_selftests(void)
 134{
 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);
 158        }
 159        fclose(file);
 160        if (!success) {
 161                puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m");
 162                poweroff();
 163        }
 164}
 165
 166static void launch_tests(void)
 167{
 168        char cmdline[4096], *success_dev;
 169        int status, fd;
 170        pid_t pid;
 171
 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");
 179        }
 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;
 196                }
 197                if (!success_dev || !strlen(success_dev))
 198                        panic("Unable to find success device");
 199
 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;
 209
 210                if (WIFEXITED(status)) {
 211                        why = "exit code";
 212                        what = WEXITSTATUS(status);
 213                } else if (WIFSIGNALED(status)) {
 214                        why = "signal";
 215                        what = WTERMSIG(status);
 216                }
 217                printf("\x1b[31m\x1b[1m[-] Tests failed with %s %d! \u2639\x1b[0m\n", why, what);
 218        }
 219}
 220
 221static void ensure_console(void)
 222{
 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;
 228                }
 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;
 235        }
 236        panic("Unable to open console device");
 237}
 238
 239static void clear_leaks(void)
 240{
 241        int fd;
 242
 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);
 249}
 250
 251static void check_leaks(void)
 252{
 253        int fd;
 254
 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);
 262
 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);
 269}
 270
 271int main(int argc, char *argv[])
 272{
 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;
 284}
 285