cleanup: VirtioNetworking refactoring to be more portable (#13783)

* cleanup: VirtioNetworking refactoring to be more portable * more refactoring * make m_guestDeviceManager private --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

Ben Hillis committed Nov 25, 2025 at 16:40 UTC 4207cc80bdb8b732d3d1e85f991d6b79a01f929e
9 files changed +340 -302
src/windows/common/CMakeLists.txt
+1 -1
@@ -63,10 +63,10 @@ set(HEADERS
63 disk.hpp
64 Distribution.h
65 filesystem.hpp
66 + HandleConsoleProgressBar.h
67 hcs.hpp
68 hcs_schema.h
69 helpers.hpp
69 - HandleConsoleProgressBar.h
70 interop.hpp
71 ExecutionContext.h
72 socket.hpp
src/windows/common/wslutil.h
+16
@@ -78,6 +78,22 @@ void CoInitializeSecurity();
78
79 void ConfigureCrt();
80
81 +/// <summary>
82 +/// Creates a COM server with user impersonation.
83 +/// </summary>
84 +template <typename Interface>
85 +wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ REFCLSID RefClsId, _In_ HANDLE UserToken)
86 +{
87 + auto revert = wil::impersonate_token(UserToken);
88 + return wil::CoCreateInstance<Interface>(RefClsId, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
89 +}
90 +
91 +template <typename Class, typename Interface>
92 +wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ HANDLE UserToken)
93 +{
94 + return CreateComServerAsUser<Interface>(__uuidof(Class), UserToken);
95 +}
96 +
97 std::wstring ConstructPipePath(_In_ std::wstring_view PipeName);
98
99 GUID CreateV5Uuid(const GUID& namespaceGuid, const std::span<const std::byte> name);
src/windows/service/exe/CMakeLists.txt
+2
@@ -17,6 +17,7 @@ set(SOURCES
17 GnsChannel.cpp
18 GnsPortTrackerChannel.cpp
19 GnsRpcServer.cpp
20 + GuestDeviceManager.cpp
21 GuestTelemetryLogger.cpp
22 Lifetime.cpp
23 LxssConsoleManager.cpp
@@ -56,6 +57,7 @@ set(HEADERS
57 GnsChannel.h
58 GnsPortTrackerChannel.h
59 GnsRpcServer.h
60 + GuestDeviceManager.h
61 GuestTelemetryLogger.h
62 INetworkingEngine.h
63 IMirroredNetworkManager.h
src/windows/service/exe/GuestDeviceManager.cpp new
+149
@@ -0,0 +1,149 @@
1 +// Copyright (C) Microsoft Corporation. All rights reserved.
2 +
3 +#include "precomp.h"
4 +#include "GuestDeviceManager.h"
5 +#include "DeviceHostProxy.h"
6 +
7 +GuestDeviceManager::GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId) :
8 + m_machineId(machineId), m_deviceHostSupport(wil::MakeOrThrow<DeviceHostProxy>(machineId, runtimeId))
9 +{
10 +}
11 +
12 +_Requires_lock_not_held_(m_lock)
13 +GUID GuestDeviceManager::AddGuestDevice(
14 + _In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
15 +{
16 + auto guestDeviceLock = m_lock.lock_exclusive();
17 + return AddHdvShareWithOptions(DeviceId, ImplementationClsid, AccessName, Options, Path, Flags, UserToken);
18 +}
19 +
20 +_Requires_lock_held_(m_lock)
21 +GUID GuestDeviceManager::AddHdvShareWithOptions(
22 + _In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
23 +{
24 + wil::com_ptr<IPlan9FileSystem> server;
25 +
26 + // Options are appended to the name with a semi-colon separator.
27 + // "name;key1=value1;key2=value2"
28 + // The AddSharePath implementation is responsible for separating them out and interpreting them.
29 + std::wstring nameWithOptions{AccessName};
30 + if (ARGUMENT_PRESENT(Options))
31 + {
32 + nameWithOptions += L";";
33 + nameWithOptions += Options;
34 + }
35 +
36 + {
37 + auto revert = wil::impersonate_token(UserToken);
38 +
39 + server = GetRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag);
40 + if (!server)
41 + {
42 + server = wil::CoCreateInstance<IPlan9FileSystem>(ImplementationClsid, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
43 + AddRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag.c_str(), server);
44 + }
45 +
46 + THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), Path, Flags));
47 + }
48 +
49 + // This requires more privileges than the user may have, so impersonation is disabled.
50 + return AddNewDevice(DeviceId, server, AccessName);
51 +}
52 +
53 +GUID GuestDeviceManager::AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag)
54 +{
55 + THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
56 + return m_deviceHostSupport->AddNewDevice(deviceId, server, tag);
57 +}
58 +
59 +void GuestDeviceManager::AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server)
60 +{
61 + THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
62 + m_deviceHostSupport->AddRemoteFileSystem(clsid, tag, server);
63 +}
64 +
65 +void GuestDeviceManager::AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken)
66 +{
67 + auto guestDeviceLock = m_lock.lock_exclusive();
68 + auto objectLifetime = CreateSectionObjectRoot(Path, UserToken);
69 +
70 + // For virtiofs hdv, the flags parameter has been overloaded. Flags are placed in the lower
71 + // 16 bits, while the shared memory size in megabytes are placed in the upper 16 bits.
72 + static constexpr auto VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT = 16;
73 + UINT32 flags = (SizeMb << VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT);
74 + WI_SetFlag(flags, VIRTIO_FS_FLAGS_TYPE_SECTIONS);
75 + (void)AddHdvShareWithOptions(VIRTIO_VIRTIOFS_DEVICE_ID, ImplementationClsid, Tag, {}, objectLifetime.Path.c_str(), flags, UserToken);
76 + m_objectDirectories.emplace_back(std::move(objectLifetime));
77 +}
78 +
79 +GuestDeviceManager::DirectoryObjectLifetime GuestDeviceManager::CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const
80 +{
81 + auto revert = wil::impersonate_token(UserToken);
82 + DWORD sessionId;
83 + DWORD bytesWritten;
84 + THROW_LAST_ERROR_IF(!GetTokenInformation(GetCurrentThreadToken(), TokenSessionId, &sessionId, sizeof(sessionId), &bytesWritten));
85 +
86 + // /Sessions/1/BaseNamedObjects/WSL/<VM ID>/<Relative Path>
87 + std::wstringstream sectionPathBuilder;
88 + sectionPathBuilder << L"\\Sessions\\" << sessionId << L"\\BaseNamedObjects" << L"\\WSL\\" << m_machineId << L"\\" << RelativeRootPath;
89 + auto sectionPath = sectionPathBuilder.str();
90 +
91 + UNICODE_STRING ntPath{};
92 + OBJECT_ATTRIBUTES attributes{};
93 + attributes.Length = sizeof(OBJECT_ATTRIBUTES);
94 + attributes.ObjectName = &ntPath;
95 + std::vector<wil::unique_handle> directoryHierarchy;
96 + auto remainingPath = std::wstring_view(sectionPath.data(), sectionPath.length());
97 + while (remainingPath.length() > 0)
98 + {
99 + // Find the next path substring, ignoring the root path backslash.
100 + auto nextDir = remainingPath;
101 + const auto separatorPos = nextDir.find(L"\\", remainingPath[0] == L'\\' ? 1 : 0);
102 + if (separatorPos != std::wstring_view::npos)
103 + {
104 + nextDir = nextDir.substr(0, separatorPos);
105 + remainingPath = remainingPath.substr(separatorPos + 1, std::wstring_view::npos);
106 +
107 + // Skip concurrent backslashes.
108 + while (remainingPath.length() > 0 && remainingPath[0] == L'\\')
109 + {
110 + remainingPath = remainingPath.substr(1, std::wstring_view::npos);
111 + }
112 + }
113 + else
114 + {
115 + remainingPath = remainingPath.substr(remainingPath.length(), std::wstring_view::npos);
116 + }
117 +
118 + attributes.RootDirectory = directoryHierarchy.size() > 0 ? directoryHierarchy.back().get() : nullptr;
119 + ntPath.Buffer = const_cast<PWCH>(nextDir.data());
120 + ntPath.Length = sizeof(WCHAR) * gsl::narrow_cast<USHORT>(nextDir.length());
121 + ntPath.MaximumLength = ntPath.Length;
122 + wil::unique_handle nextHandle;
123 + NTSTATUS status = ZwCreateDirectoryObject(&nextHandle, DIRECTORY_ALL_ACCESS, &attributes);
124 + if (status == STATUS_OBJECT_NAME_COLLISION)
125 + {
126 + status = NtOpenDirectoryObject(&nextHandle, MAXIMUM_ALLOWED, &attributes);
127 + }
128 + THROW_IF_NTSTATUS_FAILED(status);
129 + directoryHierarchy.emplace_back(std::move(nextHandle));
130 + }
131 +
132 + return {std::move(sectionPath), std::move(directoryHierarchy)};
133 +}
134 +
135 +wil::com_ptr<IPlan9FileSystem> GuestDeviceManager::GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag)
136 +{
137 + THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
138 + return m_deviceHostSupport->GetRemoteFileSystem(clsid, tag);
139 +}
140 +
141 +void GuestDeviceManager::Shutdown()
142 +try
143 +{
144 + if (m_deviceHostSupport)
145 + {
146 + m_deviceHostSupport->Shutdown();
147 + }
148 +}
149 +CATCH_LOG()
src/windows/service/exe/GuestDeviceManager.h new
+72
@@ -0,0 +1,72 @@
1 +// Copyright (C) Microsoft Corporation. All rights reserved.
2 +
3 +#pragma once
4 +
5 +#include "DeviceHostProxy.h"
6 +
7 +// Flags for virtiofs vdev device creation.
8 +#define VIRTIO_FS_FLAGS_TYPE_FILES 0x8000
9 +#define VIRTIO_FS_FLAGS_TYPE_SECTIONS 0x4000
10 +
11 +// {872270E1-A899-4AF6-B454-7193634435AD}
12 +DEFINE_GUID(VIRTIO_VIRTIOFS_DEVICE_ID, 0x872270E1, 0xA899, 0x4AF6, 0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD);
13 +
14 +// {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
15 +DEFINE_GUID(VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xe2, 0xe5, 0x78, 0x7a, 0xbc, 0xf6, 0xc2);
16 +
17 +inline const std::wstring c_defaultDeviceTag = L"default";
18 +
19 +//
20 +// Provides synchronized access to guest device operations.
21 +//
22 +class GuestDeviceManager
23 +{
24 +public:
25 + GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId);
26 +
27 + _Requires_lock_not_held_(m_lock)
28 + GUID AddGuestDevice(
29 + _In_ const GUID& DeviceId,
30 + _In_ const GUID& ImplementationClsid,
31 + _In_ PCWSTR AccessName,
32 + _In_opt_ PCWSTR Options,
33 + _In_ PCWSTR Path,
34 + _In_ UINT32 Flags,
35 + _In_ HANDLE UserToken);
36 +
37 + GUID AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag);
38 +
39 + void AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server);
40 +
41 + void AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken);
42 +
43 + wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag);
44 +
45 + void Shutdown();
46 +
47 +private:
48 + _Requires_lock_held_(m_lock)
49 + GUID AddHdvShareWithOptions(
50 + _In_ const GUID& DeviceId,
51 + _In_ const GUID& ImplementationClsid,
52 + _In_ PCWSTR AccessName,
53 + _In_opt_ PCWSTR Options,
54 + _In_ PCWSTR Path,
55 + _In_ UINT32 Flags,
56 + _In_ HANDLE UserToken);
57 +
58 + struct DirectoryObjectLifetime
59 + {
60 + std::wstring Path;
61 + // Directory objects are temporary, even if they have children, so need to keep
62 + // any created handles open in order for the directory to remain accessible.
63 + std::vector<wil::unique_handle> HierarchyLifetimes;
64 + };
65 +
66 + DirectoryObjectLifetime CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const;
67 +
68 + wil::srwlock m_lock;
69 + std::wstring m_machineId;
70 + wil::com_ptr<DeviceHostProxy> m_deviceHostSupport;
71 + _Guarded_by_(m_lock) std::vector<DirectoryObjectLifetime> m_objectDirectories;
72 +};
src/windows/service/exe/VirtioNetworking.cpp
+63 -16
@@ -2,6 +2,7 @@
2
3 #include "precomp.h"
4 #include "VirtioNetworking.h"
5 +#include "GuestDeviceManager.h"
6 #include "Stringify.h"
7 #include "stringshared.h"
8
@@ -13,15 +14,10 @@ using wsl::core::VirtioNetworking;
14 static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
15
16 VirtioNetworking::VirtioNetworking(
16 - GnsChannel&& gnsChannel,
17 - bool enableLocalhostRelay,
18 - AddGuestDeviceCallback addGuestDeviceCallback,
19 - ModifyOpenPortsCallback modifyOpenPortsCallback,
20 - GuestInterfaceStateChangeCallback guestInterfaceStateChangeCallback) :
21 - m_addGuestDeviceCallback(std::move(addGuestDeviceCallback)),
17 + GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
18 + m_guestDeviceManager(std::move(guestDeviceManager)),
19 + m_userToken(std::move(userToken)),
20 m_gnsChannel(std::move(gnsChannel)),
23 - m_modifyOpenPortsCallback(std::move(modifyOpenPortsCallback)),
24 - m_guestInterfaceStateChangeCallback(std::move(guestInterfaceStateChangeCallback)),
21 m_enableLocalhostRelay(enableLocalhostRelay)
22 {
23 }
@@ -72,11 +68,12 @@ try
68 device_options << L"nameservers=" << dns_servers;
69 }
70
75 - // Add virtio net adapter to guest
76 - m_adapterId = m_addGuestDeviceCallback(c_virtioNetworkClsid, c_virtioNetworkDeviceId, L"eth0", device_options.str().c_str());
77 -
71 auto lock = m_lock.lock_exclusive();
72
73 + // Add virtio net adapter to guest
74 + m_adapterId = m_guestDeviceManager->AddGuestDevice(
75 + c_virtioNetworkDeviceId, c_virtioNetworkClsid, L"eth0", nullptr, device_options.str().c_str(), 0, m_userToken.get());
76 +
77 hns::HNSEndpoint endpointProperties;
78 endpointProperties.ID = m_adapterId;
79 endpointProperties.IPAddress = m_networkSettings->PreferredIpAddress.AddressString;
@@ -121,8 +118,14 @@ CATCH_LOG()
118
119 void VirtioNetworking::SetupLoopbackDevice()
120 {
124 - m_localhostAdapterId = m_addGuestDeviceCallback(
125 - c_virtioNetworkClsid, c_virtioNetworkDeviceId, c_loopbackDeviceName, L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55");
121 + m_localhostAdapterId = m_guestDeviceManager->AddGuestDevice(
122 + c_virtioNetworkDeviceId,
123 + c_virtioNetworkClsid,
124 + c_loopbackDeviceName,
125 + nullptr,
126 + L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55",
127 + 0,
128 + m_userToken.get());
129
130 hns::HNSEndpoint endpointProperties;
131 endpointProperties.ID = m_localhostAdapterId;
@@ -151,7 +154,7 @@ void VirtioNetworking::StartPortTracker(wil::unique_socket&& socket)
154 m_gnsPortTrackerChannel.emplace(
155 std::move(socket),
156 [&](const SOCKADDR_INET& addr, int protocol, bool allocate) { return HandlePortNotification(addr, protocol, allocate); },
154 - [&](_In_ const std::string& interfaceName, _In_ bool up) { m_guestInterfaceStateChangeCallback(interfaceName, up); });
157 + [](const std::string&, bool) {}); // TODO: reconsider if InterfaceStateCallback is needed.
158 }
159
160 HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int protocol, bool allocate) const noexcept
@@ -185,21 +188,65 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int
188 localAddr.Ipv6.sin6_port = addr.Ipv6.sin6_port;
189 }
190 }
188 - result = m_modifyOpenPortsCallback(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
191 + result = ModifyOpenPorts(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
192 LOG_HR_IF_MSG(E_FAIL, result != S_OK, "Failure adding localhost relay port %d", localAddr.Ipv4.sin_port);
193 }
194 +
195 if (!loopback)
196 {
193 - const int localResult = m_modifyOpenPortsCallback(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
197 + const int localResult = ModifyOpenPorts(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
198 LOG_HR_IF_MSG(E_FAIL, localResult != S_OK, "Failure adding relay port %d", addr.Ipv4.sin_port);
199 if (result == 0)
200 {
201 result = localResult;
202 }
203 }
204 +
205 return result;
206 }
207
208 +int VirtioNetworking::ModifyOpenPorts(_In_ const GUID& clsid, _In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const
209 +{
210 + if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
211 + {
212 + LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", protocol);
213 + return 0;
214 + }
215 + else if (addr.si_family == AF_INET6)
216 + {
217 + // The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
218 + // IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
219 + // be handled as a separate callback to this same code.
220 + return 0;
221 + }
222 +
223 + auto lock = m_lock.lock_exclusive();
224 + const auto server = m_guestDeviceManager->GetRemoteFileSystem(clsid, c_defaultDeviceTag);
225 + if (server)
226 + {
227 + std::wstring portString = std::format(L"tag={};port_number={}", tag, addr.Ipv4.sin_port);
228 + if (protocol == IPPROTO_UDP)
229 + {
230 + portString += L";udp";
231 + }
232 +
233 + if (!isOpen)
234 + {
235 + portString += L";allocate=false";
236 + }
237 + else
238 + {
239 + wchar_t addrStr[16]; // "000.000.000.000" + null terminator
240 + RtlIpv4AddressToStringW(&addr.Ipv4.sin_addr, addrStr);
241 + portString += std::format(L";listen_addr={}", addrStr);
242 + }
243 +
244 + LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
245 + }
246 +
247 + return 0;
248 +}
249 +
250 void NETIOAPI_API_ VirtioNetworking::OnNetworkConnectivityChange(PVOID context, NL_NETWORK_CONNECTIVITY_HINT hint)
251 {
252 static_cast<VirtioNetworking*>(context)->RefreshGuestConnection(hint);
src/windows/service/exe/VirtioNetworking.h
+5 -15
@@ -6,22 +6,14 @@
6 #include "GnsChannel.h"
7 #include "WslCoreHostDnsInfo.h"
8 #include "GnsPortTrackerChannel.h"
9 +#include "GuestDeviceManager.h"
10
11 namespace wsl::core {
12
12 -using AddGuestDeviceCallback = std::function<GUID(const GUID& clsid, const GUID& deviceId, PCWSTR tag, PCWSTR options)>;
13 -using ModifyOpenPortsCallback = std::function<int(const GUID& clsid, PCWSTR tag, const SOCKADDR_INET& addr, int protocol, bool isOpen)>;
14 -using GuestInterfaceStateChangeCallback = std::function<void(const std::string& name, bool isUp)>;
15 -
13 class VirtioNetworking : public INetworkingEngine
14 {
15 public:
19 - VirtioNetworking(
20 - GnsChannel&& gnsChannel,
21 - bool enableLocalhostRelay,
22 - AddGuestDeviceCallback addGuestDeviceCallback,
23 - ModifyOpenPortsCallback modifyOpenPortsCallback,
24 - GuestInterfaceStateChangeCallback guestInterfaceStateChangeCallback);
16 + VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
17 ~VirtioNetworking() = default;
18
19 // Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
@@ -43,6 +35,7 @@ private:
35 static std::optional<ULONGLONG> FindVirtioInterfaceLuid(const SOCKADDR_INET& virtioAddress, const NL_NETWORK_CONNECTIVITY_HINT& currentConnectivityHint);
36
37 HRESULT HandlePortNotification(const SOCKADDR_INET& addr, int protocol, bool allocate) const noexcept;
38 + int ModifyOpenPorts(_In_ const GUID& clsid, _In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const;
39 void RefreshGuestConnection(NL_NETWORK_CONNECTIVITY_HINT hint) noexcept;
40 void SetupLoopbackDevice();
41 void UpdateDns(wsl::shared::hns::DNS&& dnsSettings);
@@ -50,17 +43,14 @@ private:
43
44 mutable wil::srwlock m_lock;
45
53 - AddGuestDeviceCallback m_addGuestDeviceCallback;
46 + std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
47 + wil::shared_handle m_userToken;
48 GnsChannel m_gnsChannel;
49 std::optional<GnsPortTrackerChannel> m_gnsPortTrackerChannel;
50 std::shared_ptr<networking::NetworkSettings> m_networkSettings;
51 bool m_enableLocalhostRelay;
52 GUID m_localhostAdapterId;
53 GUID m_adapterId;
60 - std::optional<NL_NETWORK_CONNECTIVITY_LEVEL_HINT> m_connectivityLevel;
61 - std::optional<NL_NETWORK_CONNECTIVITY_COST_HINT> m_connectivityCost;
62 - ModifyOpenPortsCallback m_modifyOpenPortsCallback;
63 - GuestInterfaceStateChangeCallback m_guestInterfaceStateChangeCallback;
54
55 std::optional<ULONGLONG> m_interfaceLuid;
56 ULONG m_networkMtu = 0;
src/windows/service/exe/WslCoreVm.cpp
+26 -217
@@ -39,18 +39,10 @@ using namespace std::string_literals;
39 // Start of unaddressable memory if guest only supports the minimum 36-bit addressing.
40 #define MAX_36_BIT_PAGE_IN_MB (0x1000000000 / _1MB)
41
42 -// This device type is implemented by the external virtiofs vdev.
43 -// {872270E1-A899-4AF6-B454-7193634435AD}
44 -DEFINE_GUID(VIRTIO_VIRTIOFS_DEVICE_ID, 0x872270E1, 0xA899, 0x4AF6, 0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD);
45 -
42 // This device type is implemented by the external virtio-pmem vdev.
43 // {EDBB24BB-5E19-40F4-8A0F-8224313064FD}
44 DEFINE_GUID(VIRTIO_PMEM_DEVICE_ID, 0xEDBB24BB, 0x5E19, 0x40F4, 0x8A, 0x0F, 0x82, 0x24, 0x31, 0x30, 0x64, 0xFD);
45
50 -// Flags for virtiofs vdev device creation.
51 -#define VIRTIO_FS_FLAGS_TYPE_FILES 0x8000
52 -#define VIRTIO_FS_FLAGS_TYPE_SECTIONS 0x4000
53 -
46 // Version numbers for various functionality that was backported.
47 #define NICKEL_BUILD_FLOOR 22350
48 #define VIRTIO_SERIAL_CONSOLE_COBALT_RELEASE_UBR 40
@@ -65,9 +57,6 @@ static constexpr size_t c_bootEntropy = 0x1000;
57 static constexpr auto c_localDevicesKey = L"SOFTWARE\\Microsoft\\Terminal Server Client\\LocalDevices";
58 static constexpr std::pair<uint32_t, uint32_t> c_schemaVersionNickel{2, 7};
59
68 -// {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
69 -static constexpr GUID c_pmemClassId = {0xABB755FC, 0x1B86, 0x4255, {0x83, 0xe2, 0xe5, 0x78, 0x7a, 0xbc, 0xf6, 0xc2}};
70 -
60 #define LXSS_ENABLE_GUI_APPS() (m_vmConfig.EnableGuiApps && (m_systemDistroDeviceId != ULONG_MAX))
61
62 using namespace wsl::windows::common;
@@ -78,8 +67,6 @@ using wsl::shared::Localization;
67 using wsl::windows::common::Context;
68 using wsl::windows::common::ExecutionContext;
69
81 -const std::wstring WslCoreVm::c_defaultTag = L"default"s;
82 -
70 namespace {
71 INT64
72 RequiredExtraMmioSpaceForPmemFileInMb(_In_ PCWSTR FilePath)
@@ -342,7 +329,8 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
329 m_runtimeId = wsl::windows::common::hcs::GetRuntimeId(m_system.get());
330 WI_ASSERT(IsEqualGUID(VmId, m_runtimeId));
331
345 - m_deviceHostSupport = wil::MakeOrThrow<DeviceHostProxy>(m_machineId, m_runtimeId);
332 + // Initialize the guest device manager.
333 + m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_machineId, m_runtimeId);
334
335 // Create a socket listening for connections from mini_init.
336 m_listenSocket = wsl::windows::common::hvsocket::Listen(m_runtimeId, LX_INIT_UTILITY_VM_INIT_PORT);
@@ -469,7 +457,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
457 break;
458
459 case LxMiniInitMountDeviceTypePmem:
472 - m_systemDistroDeviceId = MountFileAsPersistentMemory(c_pmemClassId, m_vmConfig.SystemDistroPath.c_str(), true);
460 + m_systemDistroDeviceId = MountFileAsPersistentMemory(m_vmConfig.SystemDistroPath.c_str(), true);
461 break;
462
463 default:
@@ -608,15 +596,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
596 else if (m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
597 {
598 m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
611 - std::move(gnsChannel),
612 - m_vmConfig.EnableLocalhostRelay,
613 - [this](const GUID& Clsid, const GUID& DeviceId, PCWSTR Tag, PCWSTR Options) {
614 - return HandleVirtioAddGuestDevice(Clsid, DeviceId, Tag, Options);
615 - },
616 - [this](const GUID& Clsid, PCWSTR Tag, const SOCKADDR_INET& Addr, int Protocol, bool IsOpen) {
617 - return HandleVirtioModifyOpenPorts(Clsid, Tag, Addr, Protocol, IsOpen);
618 - },
619 - [](const std::string&, bool) {});
599 + std::move(gnsChannel), m_vmConfig.EnableLocalhostRelay, m_guestDeviceManager, m_userToken);
600 }
601 else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
602 {
@@ -799,9 +779,9 @@ WslCoreVm::~WslCoreVm() noexcept
779 }
780
781 // Shutdown virtio device hosts.
802 - if (m_deviceHostSupport)
782 + if (m_guestDeviceManager)
783 {
804 - m_deviceHostSupport->Shutdown();
784 + m_guestDeviceManager->Shutdown();
785 }
786
787 // Call RevokeVmAccess on each VHD that was added to the utility VM. This
@@ -955,7 +935,7 @@ void WslCoreVm::AddPlan9Share(
935
936 if (m_vmConfig.EnableVirtio9p)
937 {
958 - server = m_deviceHostSupport->GetRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag);
938 + server = m_guestDeviceManager->GetRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag);
939 }
940 else
941 {
@@ -968,10 +948,10 @@ void WslCoreVm::AddPlan9Share(
948
949 if (!server)
950 {
971 - server = CreateComServerAsUser<p9fs::Plan9FileSystem, IPlan9FileSystem>(UserToken);
951 + server = wsl::windows::common::wslutil::CreateComServerAsUser<p9fs::Plan9FileSystem, IPlan9FileSystem>(UserToken);
952 if (m_vmConfig.EnableVirtio9p)
953 {
974 - m_deviceHostSupport->AddRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag, server);
954 + m_guestDeviceManager->AddRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag, server);
955
956 // Start with one device to handle the first mount request. After
957 // each mount, the Plan9 file-system will request additional
@@ -999,64 +979,8 @@ void WslCoreVm::AddPlan9Share(
979 if (addNewDevice)
980 {
981 // This requires more privileges than the user may have, so impersonation is disabled.
1002 - (void)m_deviceHostSupport->AddNewDevice(VIRTIO_PLAN9_DEVICE_ID, server, VirtIoTag);
1003 - }
1004 -}
1005 -
1006 -WslCoreVm::DirectoryObjectLifetime WslCoreVm::CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const
1007 -{
1008 - auto revert = wil::impersonate_token(UserToken);
1009 - DWORD sessionId;
1010 - DWORD bytesWritten;
1011 - THROW_LAST_ERROR_IF(!GetTokenInformation(GetCurrentThreadToken(), TokenSessionId, &sessionId, sizeof(sessionId), &bytesWritten));
1012 -
1013 - // /Sessions/1/BaseNamedObjects/WSL/<VM ID>/<Relative Path>
1014 - std::wstringstream sectionPathBuilder;
1015 - sectionPathBuilder << L"\\Sessions\\" << sessionId << L"\\BaseNamedObjects" << L"\\WSL\\" << m_machineId << L"\\" << RelativeRootPath;
1016 - auto sectionPath = sectionPathBuilder.str();
1017 -
1018 - UNICODE_STRING ntPath{};
1019 - OBJECT_ATTRIBUTES attributes{};
1020 - attributes.Length = sizeof(OBJECT_ATTRIBUTES);
1021 - attributes.ObjectName = &ntPath;
1022 - std::vector<wil::unique_handle> directoryHierarchy;
1023 - auto remainingPath = std::wstring_view(sectionPath.data(), sectionPath.length());
1024 - while (remainingPath.length() > 0)
1025 - {
1026 - // Find the next path substring, ignoring the root path backslash.
1027 - auto nextDir = remainingPath;
1028 - const auto separatorPos = nextDir.find(L"\\", remainingPath[0] == L'\\' ? 1 : 0);
1029 - if (separatorPos != std::wstring_view::npos)
1030 - {
1031 - nextDir = nextDir.substr(0, separatorPos);
1032 - remainingPath = remainingPath.substr(separatorPos + 1, std::wstring_view::npos);
1033 -
1034 - // Skip concurrent backslashes.
1035 - while (remainingPath.length() > 0 && remainingPath[0] == L'\\')
1036 - {
1037 - remainingPath = remainingPath.substr(1, std::wstring_view::npos);
1038 - }
1039 - }
1040 - else
1041 - {
1042 - remainingPath = remainingPath.substr(remainingPath.length(), std::wstring_view::npos);
1043 - }
1044 -
1045 - attributes.RootDirectory = directoryHierarchy.size() > 0 ? directoryHierarchy.back().get() : nullptr;
1046 - ntPath.Buffer = const_cast<PWCH>(nextDir.data());
1047 - ntPath.Length = sizeof(WCHAR) * gsl::narrow_cast<USHORT>(nextDir.length());
1048 - ntPath.MaximumLength = ntPath.Length;
1049 - wil::unique_handle nextHandle;
1050 - NTSTATUS status = ZwCreateDirectoryObject(&nextHandle, DIRECTORY_ALL_ACCESS, &attributes);
1051 - if (status == STATUS_OBJECT_NAME_COLLISION)
1052 - {
1053 - status = NtOpenDirectoryObject(&nextHandle, MAXIMUM_ALLOWED, &attributes);
1054 - }
1055 - THROW_IF_NTSTATUS_FAILED(status);
1056 - directoryHierarchy.emplace_back(std::move(nextHandle));
982 + (void)m_guestDeviceManager->AddNewDevice(VIRTIO_PLAN9_DEVICE_ID, server, VirtIoTag);
983 }
1058 -
1059 - return {std::move(sectionPath), std::move(directoryHierarchy)};
984 }
985
986 ULONG WslCoreVm::AttachDisk(_In_ PCWSTR Disk, _In_ DiskType Type, _In_ std::optional<ULONG> Lun, _In_ bool IsUserDisk, _In_ HANDLE UserToken)
@@ -1867,7 +1791,8 @@ void WslCoreVm::InitializeGuest()
1791 {
1792 try
1793 {
1870 - MountSharedMemoryDevice(c_virtiofsClassId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB);
1794 + m_guestDeviceManager->AddSharedMemoryDevice(
1795 + c_virtiofsClassId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
1796 m_sharedMemoryRoot = std::format(L"WSL\\{}\\wslg", m_machineId);
1797 }
1798 CATCH_LOG()
@@ -1966,7 +1891,7 @@ bool WslCoreVm::InitializeDrvFsLockHeld(_In_ HANDLE UserToken)
1891 {
1892 // Before checking whether DrvFs is already initialized, make sure any existing Plan 9 servers
1893 // are usable.
1969 - VerifyDrvFsServers();
1894 + VerifyPlan9Servers();
1895
1896 const auto elevated = wsl::windows::common::security::IsTokenElevated(UserToken);
1897 if (elevated)
@@ -2004,53 +1929,6 @@ bool WslCoreVm::IsVhdAttached(_In_ PCWSTR VhdPath)
1929 return m_attachedDisks.contains({DiskType::VHD, VhdPath});
1930 }
1931
2007 -GUID WslCoreVm::HandleVirtioAddGuestDevice(_In_ const GUID& Clsid, _In_ const GUID& DeviceId, _In_ PCWSTR Tag, _In_ PCWSTR Options)
2008 -{
2009 - auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2010 - return AddHdvShareWithOptions(DeviceId, Clsid, Tag, {}, Options, 0, m_userToken.get());
2011 -}
2012 -
2013 -int WslCoreVm::HandleVirtioModifyOpenPorts(_In_ const GUID& Clsid, _In_ PCWSTR Tag, _In_ const SOCKADDR_INET& Addr, _In_ int Protocol, _In_ bool IsOpen)
2014 -{
2015 - if (Protocol != IPPROTO_TCP && Protocol != IPPROTO_UDP)
2016 - {
2017 - LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", Protocol);
2018 - return 0;
2019 - }
2020 - else if (Addr.si_family == AF_INET6)
2021 - {
2022 - // The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
2023 - // IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
2024 - // be handled as a separate callback to this same code.
2025 - return 0;
2026 - }
2027 -
2028 - auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2029 - const auto server = m_deviceHostSupport->GetRemoteFileSystem(Clsid, c_defaultTag);
2030 - if (server)
2031 - {
2032 - std::wstring portString = std::format(L"tag={};port_number={}", Tag, Addr.Ipv4.sin_port);
2033 - if (Protocol == IPPROTO_UDP)
2034 - {
2035 - portString += L";udp";
2036 - }
2037 -
2038 - if (!IsOpen)
2039 - {
2040 - portString += L";allocate=false";
2041 - }
2042 - else
2043 - {
2044 - wchar_t addrStr[16]; // "000.000.000.000" + null terminator
2045 - RtlIpv4AddressToStringW(&Addr.Ipv4.sin_addr, addrStr);
2046 - portString += std::format(L";listen_addr={}", addrStr);
2047 - }
2048 -
2049 - LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
2050 - }
2051 - return 0;
2052 -}
2053 -
1932 WslCoreVm::DiskMountResult WslCoreVm::MountDisk(
1933 _In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options)
1934 {
@@ -2150,33 +2028,8 @@ void WslCoreVm::MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR Gue
2028 ResultMessage.Result);
2029 }
2030
2153 -void WslCoreVm::MountSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb)
2154 -{
2155 - if (!m_vmConfig.EnableVirtio)
2156 - {
2157 - return;
2158 - }
2159 -
2160 - auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2161 - MountSharedMemoryDeviceLockHeld(ImplementationClsid, Tag, Path, SizeMb);
2162 -}
2163 -
2164 -_Requires_lock_held_(m_guestDeviceLock)
2165 -void WslCoreVm::MountSharedMemoryDeviceLockHeld(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb)
2166 -{
2167 - auto objectLifetime = CreateSectionObjectRoot(Path, m_userToken.get());
2168 -
2169 - // For virtiofs hdv, the flags parameter has been overloaded. Flags are placed in the lower
2170 - // 16 bits, while the shared memory size in megabytes are placed in the upper 16 bits.
2171 - static constexpr auto VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT = 16;
2172 - UINT32 flags = (SizeMb << VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT);
2173 - WI_SetFlag(flags, VIRTIO_FS_FLAGS_TYPE_SECTIONS);
2174 - (void)AddHdvShare(VIRTIO_VIRTIOFS_DEVICE_ID, ImplementationClsid, Tag, objectLifetime.Path.c_str(), flags, m_userToken.get());
2175 - m_objectDirectories.emplace_back(std::move(objectLifetime));
2176 -}
2177 -
2031 ULONG
2179 -WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In_ PCWSTR FilePath, _In_ bool ReadOnly)
2032 +WslCoreVm::MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly)
2033 {
2034 hcs::Plan9ShareFlags flags{};
2035
@@ -2198,7 +2051,7 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In
2051 // a symlink that points to a path like:
2052 // /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0004:00/VMBUS:00/<GUID>/pcicceb:00//cceb:00:00.0/virtio1/ndbus0/region0/namespace0.0/block/pmem0
2053 // Notice the GUID in the middle of that path. That GUID is the instance ID, which is randomly
2201 - // generated by AddHdvShare. So once we find a path with the instance ID, we know that
2054 + // generated by AddGuestDevice. So once we find a path with the instance ID, we know that
2055 // eventually /dev/pmemX will appear in the guest.
2056 auto persistentMemoryLock = m_persistentMemoryLock.lock_exclusive();
2057
@@ -2209,8 +2062,8 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In
2062 // added as part of VM creation and therefore any failure will result in VM termination
2063 // (in which case there's no need to remove the device).
2064 {
2212 - auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2213 - (void)AddHdvShare(VIRTIO_PMEM_DEVICE_ID, ImplementationClsid, L"", FilePath, static_cast<UINT32>(flags), m_userToken.get());
2065 + (void)m_guestDeviceManager->AddGuestDevice(
2066 + VIRTIO_PMEM_DEVICE_ID, VIRTIO_PMEM_CLASS_ID, L"", nullptr, FilePath, static_cast<UINT32>(flags), m_userToken.get());
2067 }
2068
2069 // Wait for the pmem device to appear in the VM at /dev/pmemX. Guess the value of X given the
@@ -2259,56 +2112,6 @@ void WslCoreVm::WaitForPmemDeviceInVm(_In_ ULONG PmemId)
2112 }
2113 }
2114
2262 -_Requires_lock_held_(m_guestDeviceLock)
2263 -GUID WslCoreVm::AddHdvShareWithOptions(
2264 - _In_ const GUID& DeviceId,
2265 - _In_ const GUID& ImplementationClsid,
2266 - _In_ std::wstring_view AccessName,
2267 - _In_ std::wstring_view Options,
2268 - _In_ std::wstring_view Path,
2269 - _In_ UINT32 Flags,
2270 - _In_ HANDLE UserToken)
2271 -{
2272 - wil::com_ptr<IPlan9FileSystem> server;
2273 -
2274 - THROW_HR_IF(E_NOTIMPL, !m_vmConfig.EnableVirtio);
2275 -
2276 - // Options are appended to the name with a semi-colon separator.
2277 - // "name;key1=value1;key2=value2"
2278 - // The AddSharePath implementation is responsible for separating them out and interpreting them.
2279 - std::wstring nameWithOptions{AccessName};
2280 - if (!Options.empty())
2281 - {
2282 - nameWithOptions += L";";
2283 - nameWithOptions += Options;
2284 - }
2285 -
2286 - {
2287 - auto revert = wil::impersonate_token(UserToken);
2288 -
2289 - server = m_deviceHostSupport->GetRemoteFileSystem(ImplementationClsid, c_defaultTag);
2290 - if (!server)
2291 - {
2292 - server = CreateComServerAsUser<IPlan9FileSystem>(ImplementationClsid, UserToken);
2293 - m_deviceHostSupport->AddRemoteFileSystem(ImplementationClsid, c_defaultTag, server);
2294 - }
2295 -
2296 - const std::wstring SharePath(Path);
2297 - THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), SharePath.c_str(), Flags));
2298 - }
2299 -
2300 - // This requires more privileges than the user may have, so impersonation is disabled.
2301 - const std::wstring VirtioTag(AccessName);
2302 - return m_deviceHostSupport->AddNewDevice(DeviceId, server, VirtioTag.c_str());
2303 -}
2304 -
2305 -_Requires_lock_held_(m_guestDeviceLock)
2306 -GUID WslCoreVm::AddHdvShare(
2307 - _In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
2308 -{
2309 - return AddHdvShareWithOptions(DeviceId, ImplementationClsid, AccessName, {}, Path, Flags, UserToken);
2310 -}
2311 -
2115 _Requires_lock_held_(m_guestDeviceLock)
2116 std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken)
2117 {
@@ -2341,8 +2144,14 @@ std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_
2144 tag += std::to_wstring(m_virtioFsShares.size());
2145 WI_ASSERT(!FindVirtioFsShare(tag.c_str(), Admin));
2146
2344 - (void)AddHdvShareWithOptions(
2345 - VIRTIO_VIRTIOFS_DEVICE_ID, Admin ? c_virtiofsAdminClassId : c_virtiofsClassId, tag, key.OptionsString(), sharePath, VIRTIO_FS_FLAGS_TYPE_FILES, UserToken);
2147 + (void)m_guestDeviceManager->AddGuestDevice(
2148 + VIRTIO_VIRTIOFS_DEVICE_ID,
2149 + Admin ? c_virtiofsAdminClassId : c_virtiofsClassId,
2150 + tag.c_str(),
2151 + key.OptionsString().c_str(),
2152 + sharePath.c_str(),
2153 + VIRTIO_FS_FLAGS_TYPE_FILES,
2154 + UserToken);
2155
2156 m_virtioFsShares.emplace(std::move(key), tag);
2157 created = true;
@@ -2690,7 +2499,7 @@ std::pair<int, LX_MINI_MOUNT_STEP> WslCoreVm::UnmountVolume(_In_ const AttachedD
2499 }
2500
2501 _Requires_lock_held_(m_guestDeviceLock)
2693 -void WslCoreVm::VerifyDrvFsServers()
2502 +void WslCoreVm::VerifyPlan9Servers()
2503 {
2504 for (auto it = m_plan9Servers.begin(); it != m_plan9Servers.end();)
2505 {
src/windows/service/exe/WslCoreVm.h
+6 -53
@@ -29,6 +29,7 @@ Abstract:
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)
@@ -107,10 +108,6 @@ public:
108
109 bool IsVhdAttached(_In_ PCWSTR VhdPath);
110
110 - GUID HandleVirtioAddGuestDevice(_In_ const GUID& Clsid, _In_ const GUID& DeviceId, _In_ PCWSTR Tag, _In_ PCWSTR Options);
111 -
112 - int HandleVirtioModifyOpenPorts(_In_ const GUID& Clsid, _In_ PCWSTR Tag, _In_ const SOCKADDR_INET& Addr, _In_ int Protocol, _In_ bool IsOpen);
113 -
111 DiskMountResult MountDisk(
112 _In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
113
@@ -120,10 +117,8 @@ public:
117 ReadOnly = 0x1
118 };
119
123 - void MountSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb);
124 -
120 ULONG
126 - MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In_ PCWSTR FilePath, _In_ bool ReadOnly);
121 + MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly);
122
123 void MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR GuestPath, _In_ bool ReadOnly, _In_ LPCWSTR Name);
124
@@ -135,7 +130,7 @@ public:
130 void SaveAttachedDisksState();
131
132 _Requires_lock_held_(m_guestDeviceLock)
138 - void VerifyDrvFsServers();
133 + void VerifyPlan9Servers();
134
135 enum DiskStateFlags
136 {
@@ -172,14 +167,6 @@ private:
167 DiskStateFlags Flags;
168 };
169
175 - struct DirectoryObjectLifetime
176 - {
177 - std::wstring Path;
178 - // Directory objects are temporary, even if they have children, so need to keep
179 - // any created handles open in order for the directory to remain accessible.
180 - std::vector<wil::unique_handle> HierarchyLifetimes;
181 - };
182 -
170 struct VirtioFsShare
171 {
172 VirtioFsShare(PCWSTR Path, PCWSTR Options, bool Admin);
@@ -202,19 +189,6 @@ private:
189 _Requires_lock_held_(m_guestDeviceLock)
190 void AddPlan9Share(_In_ PCWSTR AccessName, _In_ PCWSTR Path, _In_ UINT32 Port, _In_ wsl::windows::common::hcs::Plan9ShareFlags Flags, _In_ HANDLE UserToken, _In_ PCWSTR VirtIoTag);
191
205 - _Requires_lock_held_(m_guestDeviceLock)
206 - GUID AddHdvShare(_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken);
207 -
208 - _Requires_lock_held_(m_guestDeviceLock)
209 - GUID AddHdvShareWithOptions(
210 - _In_ const GUID& DeviceId,
211 - _In_ const GUID& ImplementationClsid,
212 - _In_ std::wstring_view AccessName,
213 - _In_ std::wstring_view Options,
214 - _In_ std::wstring_view Path,
215 - _In_ UINT32 Flags,
216 - _In_ HANDLE UserToken);
217 -
192 _Requires_lock_held_(m_guestDeviceLock)
193 std::wstring AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken = nullptr);
194
@@ -223,19 +197,6 @@ private:
197
198 void CollectCrashDumps(wil::unique_socket&& socket) const;
199
226 - template <typename Interface>
227 - wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ REFCLSID RefClsId, _In_ HANDLE UserToken)
228 - {
229 - auto revert = wil::impersonate_token(UserToken);
230 - return wil::CoCreateInstance<Interface>(RefClsId, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
231 - }
232 -
233 - template <typename Class, typename Interface>
234 - wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ HANDLE UserToken)
235 - {
236 - return CreateComServerAsUser<Interface>(__uuidof(Class), UserToken);
237 - }
238 -
200 std::shared_ptr<LxssRunningInstance> CreateInstanceInternal(
201 _In_ const GUID& InstanceId,
202 _In_ const LXSS_DISTRO_CONFIGURATION& Configuration,
@@ -245,8 +206,6 @@ private:
206 _In_ bool LaunchSystemDistro = false,
207 _Out_opt_ ULONG* ConnectPort = nullptr);
208
248 - DirectoryObjectLifetime CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const;
249 -
209 _Requires_lock_held_(m_lock)
210 void EjectVhdLockHeld(_In_ PCWSTR VhdPath);
211
@@ -281,9 +240,6 @@ private:
240 DiskMountResult MountDiskLockHeld(
241 _In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
242
284 - _Requires_lock_held_(m_guestDeviceLock)
285 - void MountSharedMemoryDeviceLockHeld(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb);
286 -
243 void WaitForPmemDeviceInVm(_In_ ULONG PmemId);
244
245 void OnCrash(_In_ LPCWSTR Details);
@@ -314,12 +270,14 @@ private:
270
271 static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
272
317 - wil::srwlock m_lock;
273 wil::srwlock m_guestDeviceLock;
274 + std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
275 _Guarded_by_(m_guestDeviceLock) std::future<bool> m_drvfsInitialResult;
276 _Guarded_by_(m_guestDeviceLock) wil::unique_handle m_drvfsToken;
277 _Guarded_by_(m_guestDeviceLock) wil::unique_handle m_adminDrvfsToken;
278 _Guarded_by_(m_guestDeviceLock) std::map<VirtioFsShare, std::wstring> m_virtioFsShares;
279 + _Guarded_by_(m_guestDeviceLock) std::map<UINT32, wil::com_ptr<IPlan9FileSystem>> m_plan9Servers;
280 + wil::srwlock m_lock;
281 _Guarded_by_(m_lock) wil::unique_event m_terminatingEvent { wil::EventOptions::ManualReset };
282 _Guarded_by_(m_lock) wil::unique_event m_vmExitEvent { wil::EventOptions::ManualReset };
283 wil::unique_event m_vmCrashEvent{wil::EventOptions::ManualReset};
@@ -351,12 +309,9 @@ private:
309 wsl::shared::SocketChannel m_miniInitChannel;
310 wil::unique_socket m_notifyChannel;
311 SE_SID m_userSid;
354 - wil::com_ptr<DeviceHostProxy> m_deviceHostSupport;
312 std::shared_ptr<LxssRunningInstance> m_systemDistro;
313 _Guarded_by_(m_lock) std::bitset<MAX_VHD_COUNT> m_lunBitmap;
314 _Guarded_by_(m_lock) std::map<AttachedDisk, DiskState> m_attachedDisks;
358 - _Guarded_by_(m_guestDeviceLock) std::map<UINT32, wil::com_ptr<IPlan9FileSystem>> m_plan9Servers;
359 - _Guarded_by_(m_guestDeviceLock) std::vector<DirectoryObjectLifetime> m_objectDirectories;
315 std::tuple<std::uint32_t, std::uint32_t, std::uint32_t> m_kernelVersion;
316 std::wstring m_kernelVersionString;
317 bool m_seccompAvailable;
@@ -375,8 +330,6 @@ private:
330 _Guarded_by_(m_persistentMemoryLock) ULONG m_nextPersistentMemoryId = 0;
331
332 std::unique_ptr<wsl::core::INetworkingEngine> m_networkingEngine;
378 -
379 - static const std::wstring c_defaultTag;
333 };
334
335 DEFINE_ENUM_FLAG_OPERATORS(WslCoreVm::DiskStateFlags);