| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | common.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | This file contains common/shared information. |
| 12 | |
| 13 | --*/ |
| 14 | |
| 15 | #pragma once |
| 16 | |
| 17 | #ifndef TEMP_FAILURE_RETRY |
| 18 | #define TEMP_FAILURE_RETRY(expression) \ |
| 19 | (__extension__({ \ |
| 20 | long int __result; \ |
| 21 | do \ |
| 22 | __result = (long int)(expression); \ |
| 23 | while (__result == -1L && errno == EINTR); \ |
| 24 | __result; \ |
| 25 | })) |
| 26 | #endif |
| 27 | |
| 28 | #include <stdlib.h> |
| 29 | #include <stdio.h> |
| 30 | #include <stddef.h> |
| 31 | #include <unistd.h> |
| 32 | #include <string.h> |
| 33 | #include <errno.h> |
| 34 | #include <sched.h> |
| 35 | #include <sys/types.h> |
| 36 | #include <sys/socket.h> |
| 37 | #include <sys/stat.h> |
| 38 | #include <sys/syscall.h> |
| 39 | #include <sys/reboot.h> |
| 40 | #include <sys/un.h> |
| 41 | #include <dirent.h> |
| 42 | #include <fcntl.h> |
| 43 | #include <limits.h> |
| 44 | #include <signal.h> |
| 45 | #include <poll.h> |
| 46 | #include <utility> |
| 47 | #include <format> |
| 48 | #include <type_traits> |
| 49 | #include <new> |
| 50 | #include <thread> |
| 51 | #include <vector> |
| 52 | #include <gsl/gsl> |
| 53 | #include <gslhelpers.h> |
| 54 | #include <lxwil.h> |
| 55 | #include <cstdarg> |
| 56 | #include "lxinitshared.h" |
| 57 | #include "defs.h" |
| 58 | |
| 59 | #define ETC_FOLDER "/etc/" |
| 60 | #define NAME_ENV "NAME" |
| 61 | #define INIT_PATH "/sbin/init" |
| 62 | #define INTEROP_TIMEOUT_MS (INTEROP_TIMEOUT_SEC * 1000) |
| 63 | #define SESSION_LEADER_ACCEPT_TIMEOUT_MS (30 * 1000) |
| 64 | #define INTEROP_TIMEOUT_SEC (10) |
| 65 | #define RUN_FOLDER "/run" |
| 66 | #define WSL_SAFE_MODE_WARNING "SAFE MODE ENABLED" |
| 67 | #define CONFIG_FILE ETC_FOLDER "wsl.conf" |
| 68 | |
| 69 | extern thread_local std::string g_threadName; |
| 70 | extern int g_LogFd; |
| 71 | extern int g_TelemetryFd; |
| 72 | extern struct sigaction g_SavedSignalActions[_NSIG]; |
| 73 | |
| 74 | // |
| 75 | // N.B. The clone syscall is used directly instead of the libc wrapper, because |
| 76 | // it allows execution to continue at the point of the call with a |
| 77 | // copy-on-write stack. |
| 78 | // |
| 79 | // The clone syscall argument are architecture-specific: |
| 80 | // x86, arm, arm64: clone(flags, stack, ptid, tls, ctid) |
| 81 | // amd64: clone(flags, stack, ptid, ctid, tls) |
| 82 | // |
| 83 | |
| 84 | #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) |
| 85 | #define CLONE(_flags) syscall(SYS_clone, (_flags), NULL, NULL, NULL, NULL); |
| 86 | #elif defined(__x86_64__) |
| 87 | #define CLONE(_flags) syscall(SYS_clone, (_flags), NULL, NULL, NULL, NULL); |
| 88 | #else |
| 89 | #error CLONE function signature is architecture-specific. |
| 90 | #endif |
| 91 | |
| 92 | #define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) |
| 93 | |
| 94 | #define CLOSE(_fd) \ |
| 95 | { \ |
| 96 | if (_fd != -1 && close(_fd) < 0) \ |
| 97 | { \ |
| 98 | FATAL_ERROR("close({}) {}", _fd, errno); \ |
| 99 | } \ |
| 100 | } |
| 101 | |
| 102 | template <typename T> |
| 103 | T&& NormalizeLogArgument(T&& Argument) |
| 104 | { |
| 105 | using ArgumentType = std::remove_cv_t<std::remove_reference_t<T>>; |
| 106 | |
| 107 | if constexpr (std::is_same_v<ArgumentType, char*> || std::is_same_v<ArgumentType, const char*>) |
| 108 | { |
| 109 | if (Argument == nullptr) |
| 110 | { |
| 111 | static char NullString[] = "<null>"; |
| 112 | static ArgumentType NullArgument = NullString; |
| 113 | return static_cast<T&&>(NullArgument); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | return std::forward<T>(Argument); |
| 118 | } |
| 119 | |
| 120 | template <typename... Args> |
| 121 | auto LogImpl(int fd, const std::format_string<Args...>& format, Args&&... args) |
| 122 | { |
| 123 | auto logline = std::format(format, NormalizeLogArgument(std::forward<Args>(args))...); |
| 124 | if (logline.empty()) |
| 125 | { |
| 126 | return; |
| 127 | } |
| 128 | |
| 129 | if (logline.back() != '\n') |
| 130 | { |
| 131 | logline.push_back('\n'); |
| 132 | } |
| 133 | |
| 134 | write(fd, logline.c_str(), logline.size()); |
| 135 | } |
| 136 | |
| 137 | #define LOG_ERROR(str, ...) \ |
| 138 | { \ |
| 139 | LogImpl(g_LogFd, "<3>WSL ({} - {}) ERROR: {}:{}: " str "\n", getpid(), g_threadName.c_str(), __FUNCTION__, __LINE__, ##__VA_ARGS__); \ |
| 140 | } |
| 141 | |
| 142 | #define LOG_INFO(str, ...) \ |
| 143 | { \ |
| 144 | LogImpl(g_LogFd, "<6>WSL ({} - {}): " str "\n", getpid(), g_threadName.c_str(), ##__VA_ARGS__); \ |
| 145 | } |
| 146 | |
| 147 | #define LOG_WARNING(str, ...) \ |
| 148 | { \ |
| 149 | LogImpl(g_LogFd, "<4>WSL ({} - {}) WARNING: " str "\n", getpid(), g_threadName.c_str(), ##__VA_ARGS__); \ |
| 150 | } |
| 151 | |
| 152 | #define FATAL_ERROR_EX(status, str, ...) \ |
| 153 | { \ |
| 154 | LOG_ERROR(str, ##__VA_ARGS__); \ |
| 155 | _exit(status); \ |
| 156 | } |
| 157 | |
| 158 | #define GNS_LOG_INFO(str, ...) \ |
| 159 | { \ |
| 160 | if (g_TelemetryFd != -1) \ |
| 161 | { \ |
| 162 | LogImpl(g_TelemetryFd, "{}: {} - " str "\n", g_threadName.c_str(), __FUNCTION__, ##__VA_ARGS__); \ |
| 163 | } \ |
| 164 | } |
| 165 | |
| 166 | #define GNS_LOG_ERROR(str, ...) \ |
| 167 | { \ |
| 168 | if (g_TelemetryFd != -1) \ |
| 169 | { \ |
| 170 | LogImpl(g_TelemetryFd, "{}: {} - ERROR: " str "\n", g_threadName.c_str(), __FUNCTION__, ##__VA_ARGS__); \ |
| 171 | } \ |
| 172 | else \ |
| 173 | { \ |
| 174 | LOG_ERROR(str, ##__VA_ARGS__); \ |
| 175 | } \ |
| 176 | } |
| 177 | |
| 178 | #define FATAL_ERROR(str, ...) FATAL_ERROR_EX(1, str, ##__VA_ARGS__) |
| 179 | |
| 180 | // Some of these files need the LOG_* macros. |
| 181 | #include "retryshared.h" |
| 182 | #include "socketshared.h" |
| 183 | #include "stringshared.h" |
| 184 | |
| 185 | int InitializeLogging(bool SetStderr, wil::LogFunction* ExceptionCallback = nullptr) noexcept; |
| 186 | |
| 187 | void LogException(const char* Message, const char* Description) noexcept; |