Skip to content

Commit 4207cc8

Browse files
benhillisBen Hillis
andauthored
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>
1 parent b0df225 commit 4207cc8

File tree

9 files changed

+340
-302
lines changed

9 files changed

+340
-302
lines changed

src/windows/common/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ set(HEADERS
6363
disk.hpp
6464
Distribution.h
6565
filesystem.hpp
66+
HandleConsoleProgressBar.h
6667
hcs.hpp
6768
hcs_schema.h
6869
helpers.hpp
69-
HandleConsoleProgressBar.h
7070
interop.hpp
7171
ExecutionContext.h
7272
socket.hpp

src/windows/common/wslutil.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ void CoInitializeSecurity();
7878

7979
void ConfigureCrt();
8080

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+
8197
std::wstring ConstructPipePath(_In_ std::wstring_view PipeName);
8298

8399
GUID CreateV5Uuid(const GUID& namespaceGuid, const std::span<const std::byte> name);

src/windows/service/exe/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ set(SOURCES
1717
GnsChannel.cpp
1818
GnsPortTrackerChannel.cpp
1919
GnsRpcServer.cpp
20+
GuestDeviceManager.cpp
2021
GuestTelemetryLogger.cpp
2122
Lifetime.cpp
2223
LxssConsoleManager.cpp
@@ -56,6 +57,7 @@ set(HEADERS
5657
GnsChannel.h
5758
GnsPortTrackerChannel.h
5859
GnsRpcServer.h
60+
GuestDeviceManager.h
5961
GuestTelemetryLogger.h
6062
INetworkingEngine.h
6163
IMirroredNetworkManager.h
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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()
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
};

0 commit comments

Comments
 (0)