master
h 342 lines 11.7 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WslCoreVm.h
8
9 Abstract:
10
11 This file contains WSL Core vm function declarations.
12
13 --*/
14
15 #pragma once
16
17 #include "hcs.hpp"
18 #include "GnsChannel.h"
19 #include "LxssPort.h"
20 #include "GnsRpcServer.h"
21 #include "GnsPortTrackerChannel.h"
22 #include "Dmesg.h"
23 #include "GuestTelemetryLogger.h"
24 #include "WslCoreConfig.h"
25 #include "LxssCreateProcess.h"
26 #include "WslCoreNetworkEndpointSettings.h"
27 #include "WslSecurity.h"
28 #include "WslCoreFilesystem.h"
29 #include "INetworkingEngine.h"
30 #include "SocketChannel.h"
31 #include "DeviceHostProxy.h"
32 #include "GuestDeviceManager.h"
33
34 #define UTILITY_VM_SHUTDOWN_TIMEOUT (30 * 1000)
35 #define UTILITY_VM_TERMINATE_TIMEOUT (30 * 1000)
36
37 inline constexpr auto c_diskValueName = L"Disk";
38 inline constexpr auto c_disktypeValueName = L"DiskType";
39 inline constexpr auto c_optionsValueName = L"Options";
40 inline constexpr auto c_typeValueName = L"Type";
41 inline constexpr auto c_mountNameValueName = L"Name";
42
43 namespace wrl = Microsoft::WRL;
44
45 /// <summary>
46 /// This object tracks a running WSL Core VM.
47 /// </summary>
48 class WslCoreVm
49 {
50 WslCoreVm(const WslCoreVm&) = delete;
51 void operator=(const WslCoreVm&) = delete;
52
53 public:
54 using InitializeDrvFsCallback = std::function<LX_INIT_DRVFS_MOUNT(HANDLE)>;
55
56 static std::unique_ptr<WslCoreVm> Create(
57 _In_ const wil::shared_handle& UserToken, _In_ wsl::core::Config&& VmConfig, _In_ const GUID& VmId, _In_ InitializeDrvFsCallback InitializeDrvFs);
58
59 ~WslCoreVm() noexcept;
60
61 wil::unique_socket AcceptConnection(_In_ DWORD ReceiveTimeout = 0, _In_ const std::source_location& Location = std::source_location::current()) const;
62
63 enum class DiskType
64 {
65 Invalid = 0x0,
66 VHD = 0x1,
67 PassThrough = 0x2
68 };
69
70 ULONG AttachDisk(_In_ PCWSTR Disk, _In_ DiskType Type, _In_ std::optional<ULONG> Lun, _In_ bool IsUserDisk, _In_ HANDLE UserToken);
71
72 std::shared_ptr<LxssRunningInstance> CreateInstance(
73 _In_ const GUID& InstanceId,
74 _In_ const LXSS_DISTRO_CONFIGURATION& Configuration,
75 _In_ LX_MESSAGE_TYPE MessageType,
76 _In_ DWORD ReceiveTimeout = 0,
77 _In_ ULONG DefaultUid = LX_UID_ROOT,
78 _In_ ULONG64 ClientLifetimeId = 0,
79 _In_ ULONG ExportFlags = 0,
80 _Out_opt_ ULONG* ConnectPort = nullptr);
81
82 wil::unique_socket CreateListeningSocket() const;
83
84 wil::unique_socket CreateRootNamespaceProcess(_In_ LPCSTR Path, _In_ LPCSTR* Arguments);
85
86 std::pair<int, LX_MINI_MOUNT_STEP> DetachDisk(_In_opt_ PCWSTR Disk);
87
88 struct DiskMountResult
89 {
90 std::string MountPointName;
91 int Result;
92 LX_MINI_MOUNT_STEP Step;
93 };
94
95 void EjectVhd(_In_ PCWSTR VhdPath);
96
97 const wsl::core::Config& GetConfig() const noexcept;
98
99 GUID GetRuntimeId() const;
100
101 int GetVmIdleTimeout() const;
102
103 bool InitializeDrvFs(_In_ HANDLE UserToken);
104
105 bool IsVhdAttached(_In_ PCWSTR VhdPath);
106
107 DiskMountResult MountDisk(
108 _In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
109
110 enum MountFlags
111 {
112 None = 0x0,
113 ReadOnly = 0x1
114 };
115
116 ULONG
117 MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly);
118
119 void MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR GuestPath, _In_ bool ReadOnly, _In_ LPCWSTR Name);
120
121 void RegisterCallbacks(_In_ const std::function<void(ULONG)>& DistroExitCallback = {}, _In_ const std::function<void(GUID)>& TerminationCallback = {});
122
123 void ResizeDistribution(_In_ ULONG Lun, _In_ HANDLE OutputHandle, _In_ ULONG64 NewSize);
124
125 void TrimDistribution(_In_ ULONG Lun);
126
127 _Requires_lock_not_held_(m_lock)
128 void SaveAttachedDisksState();
129
130 _Requires_lock_held_(m_guestDeviceLock)
131 void VerifyPlan9Servers();
132
133 enum DiskStateFlags
134 {
135 Online = 0x1,
136 AccessGranted = 0x2
137 };
138
139 void TraceLoggingRundown() const noexcept;
140
141 void ValidateNetworkingMode();
142
143 private:
144 struct AttachedDisk
145 {
146 DiskType Type;
147 std::wstring Path;
148 bool User;
149
150 bool operator<(const AttachedDisk& other) const;
151 bool operator==(const AttachedDisk& other) const;
152 };
153
154 struct Mount
155 {
156 std::wstring Name;
157 std::optional<std::wstring> Options;
158 std::optional<std::wstring> Type;
159 };
160
161 struct DiskState
162 {
163 ULONG Lun;
164 std::map<ULONG, Mount> Mounts;
165 DiskStateFlags Flags;
166 wil::unique_hfile BackingFile;
167 };
168
169 struct VirtioFsShare
170 {
171 VirtioFsShare(PCWSTR Path, PCWSTR Options, bool Admin);
172
173 std::wstring Path;
174 // Mount options are stored as a map so mounts that specify mount options in different orders can be shared.
175 std::map<std::wstring, std::wstring> Options;
176 bool Admin;
177
178 std::wstring OptionsString() const;
179 bool operator<(const VirtioFsShare& other) const;
180 bool operator==(const VirtioFsShare& other) const;
181 };
182
183 WslCoreVm(_In_ wsl::core::Config&& VmConfig, _In_ InitializeDrvFsCallback InitializeDrvFs);
184
185 _Requires_lock_held_(m_guestDeviceLock)
186 void AddDrvFsShare(_In_ bool Admin, _In_ HANDLE UserToken);
187
188 _Requires_lock_held_(m_guestDeviceLock)
189 void AddPlan9Share(_In_ PCWSTR AccessName, _In_ PCWSTR Path, _In_ UINT32 Port, _In_ wsl::windows::common::hcs::Plan9ShareFlags Flags, _In_ HANDLE UserToken, _In_ PCWSTR VirtIoTag);
190
191 _Requires_lock_held_(m_guestDeviceLock)
192 std::tuple<std::wstring, std::wstring, std::wstring> AddVirtioFsShare(
193 _In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken = nullptr);
194
195 _Requires_lock_held_(m_lock)
196 ULONG AttachDiskLockHeld(_In_ PCWSTR Disk, _In_ DiskType Type, _In_ MountFlags Flags, _In_ std::optional<ULONG> Lun, _In_ bool IsUserDisk, _In_ HANDLE UserToken);
197
198 void CollectCrashDumps(wil::unique_socket&& socket) const;
199
200 std::shared_ptr<LxssRunningInstance> CreateInstanceInternal(
201 _In_ const GUID& InstanceId,
202 _In_ const LXSS_DISTRO_CONFIGURATION& Configuration,
203 _In_ DWORD ReceiveTimeout = 0,
204 _In_ ULONG DefaultUid = LX_UID_ROOT,
205 _In_ ULONG64 ClientLifetimeId = 0,
206 _In_ bool LaunchSystemDistro = false,
207 _Out_opt_ ULONG* ConnectPort = nullptr);
208
209 _Requires_lock_held_(m_lock)
210 void EjectVhdLockHeld(_In_ PCWSTR VhdPath);
211
212 _Requires_lock_held_(m_guestDeviceLock)
213 std::optional<VirtioFsShare> FindVirtioFsShare(_In_ PCWSTR tag, _In_ std::optional<bool> Admin = {}) const;
214
215 _Requires_lock_held_(m_lock)
216 void FreeLun(_In_ ULONG Lun);
217
218 std::wstring GenerateConfigJson();
219
220 static std::pair<int, LX_MINI_MOUNT_STEP> GetMountResult(_In_ wsl::shared::SocketChannel& Channel);
221
222 void GrantVmWorkerProcessAccessToDisk(_In_ PCWSTR Disk, _In_opt_ HANDLE UserToken) const;
223
224 void Initialize(const GUID& VmId, const wil::shared_handle& UserToken);
225
226 void InitializeGuest();
227
228 _Requires_lock_held_(m_guestDeviceLock)
229 bool InitializeDrvFsLockHeld(_In_ HANDLE UserToken);
230
231 bool IsDnsTunnelingSupported() const;
232
233 _Requires_lock_held_(m_lock)
234 DiskMountResult MountDiskLockHeld(
235 _In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
236
237 void WaitForPmemDeviceInVm(_In_ ULONG PmemId);
238
239 void OnCrash(_In_ LPCWSTR Details);
240
241 void OnExit(_In_opt_ PCWSTR ExitDetails);
242
243 void ReadGuestCapabilities();
244
245 _Requires_lock_held_(m_lock)
246 ULONG ReserveLun(_In_ std::optional<ULONG> Lun = {});
247
248 void RestorePassthroughDiskState(_In_ LPCWSTR Disk) const;
249
250 _Requires_lock_held_(m_lock)
251 static void SaveDiskState(_In_ HKEY Key, _In_ const AttachedDisk& Disk, _In_ const DiskState& State, _In_ const DiskType& DiskType);
252
253 _Requires_lock_held_(m_lock)
254 std::pair<int, LX_MINI_MOUNT_STEP> UnmountDisk(_In_ const AttachedDisk& Disk, _Inout_ DiskState& State);
255
256 _Requires_lock_held_(m_lock)
257 std::pair<int, LX_MINI_MOUNT_STEP> UnmountVolume(_In_ const AttachedDisk& Disk, _In_ ULONG PartitionIndex, _In_ PCWSTR Name);
258
259 void VirtioFsWorker(_In_ const wil::unique_socket& socket);
260
261 std::vector<char> ProcessVirtioFsRequest(_In_ gsl::span<gsl::byte> Request);
262
263 static std::string s_GetMountTargetName(_In_ PCWSTR Disk, _In_opt_ PCWSTR Name, _In_ int PartitionIndex);
264
265 static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
266
267 wil::srwlock m_guestDeviceLock;
268 std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
269 _Guarded_by_(m_guestDeviceLock) std::future<bool> m_drvfsInitialResult;
270 _Guarded_by_(m_guestDeviceLock) wil::unique_handle m_drvfsToken;
271 _Guarded_by_(m_guestDeviceLock) wil::unique_handle m_adminDrvfsToken;
272 _Guarded_by_(m_guestDeviceLock) std::map<VirtioFsShare, std::wstring> m_virtioFsShares;
273 _Guarded_by_(m_guestDeviceLock) std::optional<GUID> m_virtioFsDevice;
274 _Guarded_by_(m_guestDeviceLock) std::optional<GUID> m_adminVirtioFsDevice;
275 _Guarded_by_(m_guestDeviceLock) std::map<UINT32, wil::com_ptr<IPlan9FileSystem>> m_plan9Servers;
276 wil::srwlock m_lock;
277 _Guarded_by_(m_lock) wil::unique_event m_terminatingEvent { wil::EventOptions::ManualReset };
278 _Guarded_by_(m_lock) wil::unique_event m_vmExitEvent { wil::EventOptions::ManualReset };
279 wil::unique_event m_vmCrashEvent{wil::EventOptions::ManualReset};
280 std::optional<std::filesystem::path> m_vmCrashLogFile;
281
282 wil::srwlock m_exitCallbackLock;
283 std::wstring m_exitDetails;
284 std::wstring m_machineId;
285 GUID m_runtimeId;
286 wsl::core::Config m_vmConfig;
287 InitializeDrvFsCallback m_initializeDrvFs;
288 std::wstring m_comPipe0;
289 std::wstring m_comPipe1;
290 int m_pageReportingOrder;
291 WslTraceLoggingClient m_traceClient;
292 std::filesystem::path m_rootFsPath;
293 std::filesystem::path m_tempPath;
294 wil::shared_handle m_userToken;
295 wil::unique_handle m_restrictedToken;
296 bool m_swapFileCreated;
297 bool m_localDevicesKeyCreated;
298 bool m_tempDirectoryCreated;
299 bool m_enableInboxGpuLibs;
300 bool m_defaultKernel = true;
301 bool m_privateKernelModules = false;
302 LX_MINI_INIT_MOUNT_DEVICE_TYPE m_systemDistroDeviceType = LxMiniInitMountDeviceTypeInvalid;
303 ULONG m_systemDistroDeviceId = ULONG_MAX;
304 ULONG m_kernelModulesDeviceId = ULONG_MAX;
305 wsl::windows::common::hcs::unique_hcs_system m_system;
306 wil::unique_socket m_listenSocket;
307 std::function<void(GUID)> m_onExit;
308 wsl::shared::SocketChannel m_miniInitChannel;
309 wil::unique_socket m_notifyChannel;
310 SE_SID m_userSid;
311 std::shared_ptr<LxssRunningInstance> m_systemDistro;
312 _Guarded_by_(m_lock) std::bitset<MAX_VHD_COUNT> m_lunBitmap;
313 _Guarded_by_(m_lock) std::map<AttachedDisk, DiskState> m_attachedDisks;
314 std::tuple<std::uint32_t, std::uint32_t, std::uint32_t> m_kernelVersion;
315 std::wstring m_kernelVersionString;
316 bool m_seccompAvailable;
317 uint64_t m_hvPciSwiotlbBase = 0;
318 uint64_t m_hvPciSwiotlbSize = 0;
319 std::wstring m_sharedMemoryRoot;
320 std::filesystem::path m_installPath;
321 std::wstring m_userProfile;
322 wsl::windows::common::helpers::WindowsVersion m_windowsVersion;
323 std::shared_ptr<DmesgCollector> m_dmesgCollector;
324 std::shared_ptr<GuestTelemetryLogger> m_gnsTelemetryLogger;
325 std::wstring m_debugShellPipe;
326 std::thread m_distroExitThread;
327 std::thread m_virtioFsThread;
328 std::thread m_crashDumpCollectionThread;
329
330 wil::srwlock m_persistentMemoryLock;
331 _Guarded_by_(m_persistentMemoryLock) ULONG m_nextPersistentMemoryId = 0;
332
333 std::unique_ptr<wsl::core::INetworkingEngine> m_networkingEngine;
334
335 // Job object that terminates child processes (wslhost.exe, wslrelay.exe)
336 // when the VM shuts down.
337 wil::unique_handle m_processJobObject;
338 };
339
340 DEFINE_ENUM_FLAG_OPERATORS(WslCoreVm::DiskStateFlags);
341
342 DEFINE_ENUM_FLAG_OPERATORS(WslCoreVm::MountFlags);