master
h 446 lines 11.9 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 config.c
8
9 Abstract:
10
11 This file contains information related to configuring a running instance.
12
13 --*/
14
15 #pragma once
16
17 #include <unistd.h>
18 #include <pwd.h>
19 #include <optional>
20 #include <set>
21 #include <string_view>
22 #include <optional>
23 #include <functional>
24 #include "SocketChannel.h"
25 #include "WslDistributionConfig.h"
26
27 #define WSL_USE_VIRTIO_9P() (WI_IsFlagSet(UtilGetFeatureFlags(), LxInitFeatureVirtIo9p))
28 #define WSL_USE_VIRTIO_FS() (WI_IsFlagSet(UtilGetFeatureFlags(), LxInitFeatureVirtIoFs))
29 #define WSLG_SHARED_FOLDER "wslg"
30
31 #define INIT_MAKE_SECURITY(_uid, _gid, _mode) {_uid, _gid, _mode}
32 #define INIT_ANY_SYMLINK(_source, _target) \
33 { \
34 InitStartupTypeSymlink, \
35 { \
36 .Symlink = INIT_MAKE_SYMLINK(_source, _target) \
37 } \
38 }
39 #define INIT_ANY_DIRECTORY(_path, _uid, _gid, _mode) \
40 { \
41 InitStartupTypeDirectory, \
42 { \
43 .Directory = INIT_MAKE_DIRECTORY(_path, _uid, _gid, _mode) \
44 } \
45 }
46 #define INIT_ANY_MOUNT(_mount, _filesystem, _flags) \
47 { \
48 InitStartupTypeMount, \
49 { \
50 .Mount = INIT_MAKE_MOUNT(_mount, _filesystem, NULL, NULL, INIT_MAKE_SECURITY(0, 0, 0), _flags, false) \
51 } \
52 }
53
54 #define INIT_ANY_MOUNT_OPTION(_mount, _filesystem, _option, _flags) \
55 { \
56 InitStartupTypeMount, \
57 { \
58 .Mount = INIT_MAKE_MOUNT(_mount, _filesystem, NULL, (_option), INIT_MAKE_SECURITY(0, 0, 0), _flags, false) \
59 } \
60 }
61
62 #define INIT_ANY_MOUNT_DEVICE(_mount, _filesystem, _device, _flags) \
63 { \
64 InitStartupTypeMount, \
65 { \
66 .Mount = INIT_MAKE_MOUNT(_mount, _filesystem, (_device), NULL, INIT_MAKE_SECURITY(0, 0, 0), _flags, false) \
67 } \
68 }
69
70 #define INIT_ANY_MOUNT_DEVICE_OPTION(_mount, _filesystem, _device, _option, _flags) \
71 { \
72 InitStartupTypeMount, \
73 { \
74 .Mount = INIT_MAKE_MOUNT(_mount, _filesystem, (_device), (_option), INIT_MAKE_SECURITY(0, 0, 0), _flags, false) \
75 } \
76 }
77
78 #define INIT_ANY_MOUNT_DEVICE_OPTION_IGNORE_FAILURE(_mount, _filesystem, _device, _option, _flags) \
79 { \
80 InitStartupTypeMount, \
81 { \
82 .Mount = INIT_MAKE_MOUNT(_mount, _filesystem, (_device), (_option), INIT_MAKE_SECURITY(0, 0, 0), _flags, true) \
83 } \
84 }
85
86 #define INIT_ANY_NODE(_path, _uid, _gid, _mode, _major, _minor) \
87 { \
88 InitStartupTypeNode, \
89 { \
90 .Node = INIT_MAKE_NODE(_path, _uid, _gid, _mode, _major, _minor) \
91 } \
92 }
93 #define INIT_ANY_FILE(_filename, _mode) \
94 { \
95 InitStartupTypeFile, \
96 { \
97 .File = INIT_MAKE_FILE(_filename, _mode) \
98 } \
99 }
100 #define INIT_MAKE_MOUNT(_mount, _filesystem, _devicename, _options, _directorysecurity, _flags, _ignorefailure) \
101 {(_mount), (_filesystem), _devicename, _options, _directorysecurity, _flags, _ignorefailure}
102 #define INIT_MAKE_SYMLINK(_source, _target) {(_source), (_target)}
103 #define INIT_MAKE_DIRECTORY(_path, _uid, _gid, _mode) \
104 { \
105 (_path), \
106 { \
107 _uid, _gid, _mode \
108 } \
109 }
110 #define INIT_MAKE_FILE(_filename, _mode) {(_filename), _mode}
111 #define INIT_MAKE_NODE(_path, _uid, _gid, _mode, _major, _minor) {(_path), {_uid, _gid, _mode}, _major, _minor}
112
113 //
114 // Major devices.
115 //
116
117 #define INIT_DEV_MEM_MAJOR_NUMBER (1)
118 #define INIT_DEV_TTY_MAJOR_NUMBER (4)
119 #define INIT_DEV_ALT_TTY_MAJOR_NUMBER (5)
120 #define INIT_DEV_MISC_MAJOR_NUMBER (10)
121
122 //
123 // LxBus Device.
124 //
125 // TODO_LX: The minor number is in the dynamic allocation range for misc
126 // devices. Once dynamic allocation is supported it should probably
127 // be actually dynamically allocated.
128 //
129
130 #define INIT_DEV_LXBUS_MINOR_NUMBER (50)
131 #define INIT_DEV_LXBUS_MAJOR_NUMBER INIT_DEV_MISC_MAJOR_NUMBER
132
133 //
134 // Full Device.
135 //
136
137 #define INIT_DEV_FULL_MINOR_NUMBER (7)
138 #define INIT_DEV_FULL_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
139
140 //
141 // Log devices.
142 //
143
144 #define INIT_DEV_LOG_KMSG_MINOR_NUMBER (11)
145 #define INIT_DEV_LOG_KMSG_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
146
147 //
148 // Null Device.
149 //
150
151 #define INIT_DEV_NULL_MINOR_NUMBER (3)
152 #define INIT_DEV_NULL_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
153
154 //
155 // Zero Device.
156 //
157
158 #define INIT_DEV_ZERO_MINOR_NUMBER (5)
159 #define INIT_DEV_ZERO_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
160
161 //
162 // PTMX Device.
163 //
164
165 #define INIT_DEV_PTM_MINOR_NUMBER (2)
166 #define INIT_DEV_PTM_MAJOR_NUMBER INIT_DEV_ALT_TTY_MAJOR_NUMBER
167
168 //
169 // PTS Devices.
170 //
171
172 #define INIT_DEV_PTS_MAJOR_NUMBER (136)
173
174 //
175 // Random device.
176 //
177
178 #define INIT_DEV_RANDOM_MINOR_NUMBER (8)
179 #define INIT_DEV_RANDOM_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
180
181 //
182 // TTY device.
183 //
184
185 #define INIT_DEV_TTY0_MINOR_NUMBER (0)
186 #define INIT_DEV_TTY_MINOR_NUMBER_FIRST_VIRTUAL (1)
187 #define INIT_DEV_TTY_MINOR_NUMBER_MAX_VIRTUAL (64)
188 #define INIT_DEV_TTY_MINOR_NUMBER_FIRST_SERIAL (64)
189 #define INIT_DEV_TTY_MINOR_NUMBER_MAX_SERIAL (256)
190
191 #define INIT_DEV_TTY_SERIAL_MODE (S_IFCHR | 0660)
192 #define INIT_DEV_TTY_SERIAL_GID DIALOUT_GID
193 #define INIT_DEV_TTY_SERIAL_UID ROOT_UID
194 #define INIT_DEV_TTY_SERIAL_FORMAT "/dev/ttyS{}"
195
196 #define INIT_DEV_TTYCT_MINOR_NUMBER (0)
197 #define INIT_DEV_TTYCT_MAJOR_NUMBER INIT_DEV_ALT_TTY_MAJOR_NUMBER
198
199 //
200 // URandom Device.
201 //
202
203 #define INIT_DEV_URANDOM_MINOR_NUMBER (9)
204 #define INIT_DEV_URANDOM_MAJOR_NUMBER INIT_DEV_MEM_MAJOR_NUMBER
205
206 //
207 // UID and GID values.
208 //
209
210 #define DIALOUT_GID (20)
211 #define ROOT_GID (0)
212 #define ROOT_UID (0)
213 #define TTY_GID (5)
214 #define TTY_MODE (0660)
215
216 //
217 // Initialization helpers.
218 //
219
220 typedef struct _INIT_SECURITY
221 {
222 uid_t Uid;
223 gid_t Gid;
224 mode_t Mode;
225 } INIT_SECURITY, *PINIT_SECURITY;
226
227 using PCINIT_SECURITY = const INIT_SECURITY*;
228
229 typedef struct _INIT_STARTUP_MOUNT
230 {
231 const char* MountLocation;
232 const char* FileSystemType;
233 const char* DeviceName;
234 const char* MountOptions;
235 INIT_SECURITY DirectorySecurity;
236 unsigned long Flags;
237 bool IgnoreFailure;
238 } INIT_STARTUP_MOUNT, *PINIT_STARTUP_MOUNT;
239
240 using PCINIT_STARTUP_MOUNT = const INIT_STARTUP_MOUNT*;
241
242 typedef struct _INIT_STARTUP_SYMBOLIC_LINK
243 {
244 const char* Source;
245 const char* Target;
246 } INIT_STARTUP_SYMBOLIC_LINK, *PINIT_STARTUP_SYMBOLIC_LINK;
247
248 using PCINIT_STARTUP_SYMBOLIC_LINK = const INIT_STARTUP_SYMBOLIC_LINK*;
249
250 typedef struct _INIT_STARTUP_DIRECTORY
251 {
252 const char* Path;
253 INIT_SECURITY Security;
254 } INIT_STARTUP_DIRECTORY, *PINIT_STARTUP_DIRECTORY;
255
256 using PCINIT_STARTUP_DIRECTORY = const INIT_STARTUP_DIRECTORY*;
257
258 typedef struct _INIT_STARTUP_FILE
259 {
260 const char* FileName;
261 mode_t Mode;
262 } INIT_STARTUP_FILE, *PINIT_STARTUP_FILE;
263
264 using PCINIT_STARTUP_FILE = const INIT_STARTUP_FILE*;
265
266 typedef struct _INIT_STARTUP_NODE
267 {
268 const char* Path;
269 INIT_SECURITY Security;
270 unsigned int MajorNumber;
271 unsigned int MinorNumber;
272 } INIT_STARTUP_NODE, *PINIT_STARTUP_NODE;
273
274 using PCINIT_STARTUP_NODE = const INIT_STARTUP_NODE*;
275
276 typedef enum _INIT_STARTUP_TYPE
277 {
278 InitStartupTypeDirectory,
279 InitStartupTypeMount,
280 InitStartupTypeNode,
281 InitStartupTypeSymlink,
282 InitStartupTypeFile
283 } INIT_STARTUP_TYPE,
284 *PINIT_STARTUP_TYPE;
285
286 typedef struct _INIT_STARTUP_ANY
287 {
288 INIT_STARTUP_TYPE Type;
289
290 union
291 {
292 INIT_STARTUP_DIRECTORY Directory;
293 INIT_STARTUP_MOUNT Mount;
294 INIT_STARTUP_NODE Node;
295 INIT_STARTUP_SYMBOLIC_LINK Symlink;
296 INIT_STARTUP_FILE File;
297 } u;
298 } INIT_STARTUP_ANY, *PINIT_STARTUP_ANY;
299
300 using PCINIT_STARTUP_ANY = const INIT_STARTUP_ANY*;
301
302 class EnvironmentBlock
303 {
304 public:
305 EnvironmentBlock() = default;
306
307 EnvironmentBlock(const char* Buffer, unsigned short Count)
308 {
309 m_variables.reserve(Count);
310 for (unsigned short Index = 0; Index < Count; Index += 1)
311 {
312 std::string entry{Buffer};
313 const auto size = entry.size();
314 m_variables.push_back(std::move(entry));
315 Buffer += size + 1;
316 }
317 }
318
319 void AddVariable(std::string_view Name, std::string_view Value)
320 {
321 std::string entry{Name};
322 entry += "=";
323 auto found = std::find_if(
324 m_variables.begin(), m_variables.end(), [&entry](const auto& variable) { return (variable.find(entry) == 0); });
325
326 entry += Value;
327 if (found != m_variables.end())
328 {
329 *found = std::move(entry);
330 }
331 else
332 {
333 m_variables.push_back(std::move(entry));
334 }
335 }
336
337 int AddVariableNoThrow(std::string_view Name, std::string_view Value)
338 try
339 {
340 AddVariable(Name, Value);
341 return 0;
342 }
343
344 CATCH_RETURN_ERRNO()
345
346 std::string_view GetVariable(std::string_view Name)
347 {
348 std::string prefix{Name};
349 prefix += "=";
350 auto found = std::find_if(
351 m_variables.begin(), m_variables.end(), [&prefix](const auto& variable) { return (variable.find(prefix) == 0); });
352
353 std::string_view value{};
354 if (found != m_variables.end())
355 {
356 value = *found;
357 value = value.substr(prefix.size());
358 }
359
360 return value;
361 }
362
363 std::vector<const char*> Variables()
364 {
365 std::vector<const char*> variables;
366 variables.reserve(m_variables.size() + 1);
367 std::for_each(
368 m_variables.begin(), m_variables.end(), [&variables](const auto& variable) { variables.push_back(variable.c_str()); });
369
370 variables.push_back(nullptr);
371 return variables;
372 }
373
374 private:
375 std::vector<std::string> m_variables;
376 };
377
378 void ConfigAppendToPath(EnvironmentBlock& Environment, std::string_view PathElement);
379
380 wsl::linux::WslDistributionConfig ConfigInitializeCommon(struct sigaction* SavedSignalActions);
381
382 int ConfigInitializeEntry(PCINIT_STARTUP_ANY AnyEntry);
383
384 int ConfigInitializeVmMode(bool Elevated, wsl::linux::WslDistributionConfig& Config);
385
386 int ConfigInitializeWsl(void);
387
388 void ConfigInitializeX11(const wsl::linux::WslDistributionConfig& Config);
389
390 void ConfigCreateResolvConfSymlink(const wsl::linux::WslDistributionConfig& Config);
391
392 int ConfigCreateResolvConfSymlinkTarget(void);
393
394 EnvironmentBlock ConfigCreateEnvironmentBlock(PLX_INIT_CREATE_PROCESS_COMMON Common, const wsl::linux::WslDistributionConfig& Config);
395
396 std::optional<unsigned int> ConfigGetDriveLetter(std::string_view MountSource);
397
398 std::set<std::pair<unsigned int, std::string>> ConfigGetMountedDrvFsVolumes(void);
399
400 std::vector<std::pair<std::string, std::string>> ConfigGetWslgEnvironmentVariables(const wsl::linux::WslDistributionConfig& Config);
401
402 void ConfigHandleInteropMessage(
403 wsl::shared::Transaction& Transaction,
404 wsl::shared::SocketChannel& InteropChannel,
405 bool Elevated,
406 gsl::span<gsl::byte> Message,
407 const MESSAGE_HEADER* Header,
408 const wsl::linux::WslDistributionConfig& Config);
409
410 void ConfigInitializeCgroups(wsl::linux::WslDistributionConfig& Config);
411
412 int ConfigInitializeInstance(const std::function<void(const gsl::span<gsl::byte>&)>& SendResponse, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config);
413
414 void ConfigMountDrvFsVolumes(unsigned int DrvFsVolumes, uid_t OwnerUid, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config);
415
416 void ConfigMountFsTab(bool Elevated);
417
418 int ConfigReconfigureResolvConfSymlink(const wsl::linux::WslDistributionConfig& Config);
419
420 int ConfigRegisterBinfmtInterpreter(void);
421
422 int ConfigSetMountNamespace(bool Elevated);
423
424 int ConfigRemountDrvFs(gsl::span<gsl::byte> Buffer, wsl::shared::Transaction& Transaction, const wsl::linux::WslDistributionConfig& Config);
425
426 int ConfigRemountDrvFsImpl(gsl::span<gsl::byte> Buffer, const wsl::linux::WslDistributionConfig& Config);
427
428 void ConfigUpdateLanguage(EnvironmentBlock& Environment);
429
430 void ConfigUpdateNetworkInformation(gsl::span<gsl::byte> Buffer, const wsl::linux::WslDistributionConfig& Config);
431
432 template <>
433 struct std::formatter<INIT_STARTUP_TYPE, char>
434 {
435 template <typename TCtx>
436 constexpr auto parse(TCtx& ctx)
437 {
438 return ctx.begin();
439 }
440
441 template <typename TCtx>
442 auto format(INIT_STARTUP_TYPE str, TCtx& ctx) const
443 {
444 return std::format_to(ctx.out(), "{}", static_cast<int>(str));
445 }
446 };