merge master -> feature/wsl-for-apps (#13785)

* wslsettings: allow OOBE window to close with escape key (#13686)

* wslsettings: allow OOBE windows to close with escape key

* fix memory leak

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Localization change from build: 133610492 (#13704)

Co-authored-by: WSL localization <noreply@microsoft.com>

* wslsettings: fix OOBE text truncation at 200% text scaling (#13693)

* wslsettings: fix OOBE text truncation at 200% text scaling

Add text scaling factor to window resize calculation and make hero image height responsive to text scaling. Increase minimum window size for better accessibility. Fix MAS 1.4.4 compliance for OOBE dialog.

* pr feedback

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* wslsettings: add underlines to links in about page (#13703)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* .clang-format: add InsertBraces: true and minor fix to FormatSource.ps1 (#13712)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Localization change from build: 134015316 (#13731)

Co-authored-by: WSL localization <noreply@microsoft.com>

* wslsettings: ensure selected setting is auto-expanded and selected (#13689)

* wslsettings: ensure selected setting is auto-selected

Implement keyboard focus management for SettingsExpander controls across settings pages. This resolves an accessibility issue reported internally.

* add asserts

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* build: fix minor compiler errors when building with VS2026 (#13744)

* build: fix minor compiler errors when building with VS2026

* s

* use VS2022 for clang format and cross compiling

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* chore(distributions): Almalinux auto-update - 20251119 12:04:35 (#13743)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Mask systemd-networkd-wait-online.service during boot (#13611)

* deps: update a number of NuGet packages to the latest available versions (#13728)

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* Notice change from build: 134267142 (#13751)

Co-authored-by: WSL notice <noreply@microsoft.com>

* Add *.slnx to .gitignore (#13754)

* Fix service crash when collecting a linux crash dump when maxCrashDumpCount is set to 0 (#13755)

* Fix service crash when collecting a linux crash dump when maxCrashDumpCount is set to 0

* Move the check inside the function

* cleanup: VirtioNetworking refactoring (#13760)

* cleanup: update VirtioNetworking class to not rely on the WslCoreConfig struct

* cleanup: simplify VirtioNetworking construction

* remove old constructor and other cleanup

* more minor cleanup

* string cleanup in HandleVirtioModifyOpenPorts

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* cleanup: switch from Microsoft::WRL::ComPtr to wil::com_ptr (#13767)

* cleanup: switch from Microsoft::WRL::ComPtr to wil::com_ptr

* reformat

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

* chore(distributions): Almalinux auto-update - 20251124 17:13:02 (#13780)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Notice change from build: 134527933 (#13782)

Co-authored-by: WSL notice <noreply@microsoft.com>

* 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>

---------

Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Blue <OneBlue@users.noreply.github.com>
Co-authored-by: WSL localization <noreply@microsoft.com>
Co-authored-by: AlmaLinux Autobot <107999298+almalinuxautobot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Ben Hillis 2025-11-25 18:19:42 -08:00 committed by GitHub
parent 47117005db
commit 256e637795
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 408 additions and 1711 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ tmp
/.vs/
/.vscode/
*.sln
*.slnx
*.user
*.csproj
*.vcxproj

1368
NOTICE.txt

File diff suppressed because it is too large Load Diff

View File

@ -151,12 +151,12 @@
"FriendlyName": "AlmaLinux OS 10",
"Default": true,
"Amd64Url": {
"Url": "https://github.com/AlmaLinux/wsl-images/releases/download/v10.0.20250529.0/AlmaLinux-10.0_x64_20250529.0.wsl",
"Sha256": "6775711048b86743588da7173ab45ca449b5c50a72fb87635313f059a9813d4b"
"Url": "https://github.com/AlmaLinux/wsl-images/releases/download/v10.1.20251124.0/AlmaLinux-10.1_x64_20251124.0.wsl",
"Sha256": "24e8fa286a4081979d97e83a227fb89f332bcf731fe4b422679a3b455ab0be37"
},
"Arm64Url": {
"Url": "https://github.com/AlmaLinux/wsl-images/releases/download/v10.0.20250529.0/AlmaLinux-10.0_ARM64_20250529.0.wsl",
"Sha256": "bc424bd9f954d36e871d4d874d35bc25e3ea7bdfe48337c30b927ed73a79b2fa"
"Url": "https://github.com/AlmaLinux/wsl-images/releases/download/v10.1.20251124.0/AlmaLinux-10.1_ARM64_20251124.0.wsl",
"Sha256": "20700a4467214074f8a1a3d4e0e1cad25af36b8127d047ab6d5b4a1355e998b8"
}
}
],

View File

@ -6,15 +6,15 @@
<package id="Microsoft.Direct3D.Linux" version="1.611.1-81528511" targetFramework="native" />
<package id="Microsoft.DXCore.Linux.amd64fre" version="10.0.26100.1-240331-1435.ge-release" targetFramework="native" />
<package id="Microsoft.DXCore.Linux.arm64fre" version="10.0.26100.1-240331-1435.ge-release" targetFramework="native" />
<package id="Microsoft.Extensions.Hosting" version="9.0.8" />
<package id="Microsoft.Extensions.Hosting" version="10.0.0" />
<package id="Microsoft.Identity.MSAL.WSL.Proxy" version="0.1.1" />
<package id="Microsoft.NETCore.App.Runtime.win-arm64" version="9.0.10" />
<package id="Microsoft.NETCore.App.Runtime.win-x64" version="9.0.10" />
<package id="Microsoft.RemoteDesktop.Client.MSRDC.SessionHost" version="1.2.6353" />
<package id="Microsoft.Taef" version="10.97.250317001" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.250325.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.NET.Ref" version="10.0.26100.75" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250606001" />
<package id="Microsoft.NETCore.App.Runtime.win-arm64" version="10.0.0" />
<package id="Microsoft.NETCore.App.Runtime.win-x64" version="10.0.0" />
<package id="Microsoft.RemoteDesktop.Client.MSRDC.SessionHost" version="1.2.6676" />
<package id="Microsoft.Taef" version="10.100.251104001" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.251108.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.NET.Ref" version="10.0.26100.81" />
<package id="Microsoft.WindowsAppSDK" version="1.8.251106002" />
<package id="Microsoft.WSL.bsdtar" version="0.0.2-2" />
<package id="Microsoft.WSL.Dependencies.amd64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
<package id="Microsoft.WSL.Dependencies.arm64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
@ -27,8 +27,8 @@
<package id="Microsoft.WSL.WSLATestDistro" version="0.1.0" />
<package id="Microsoft.WSLg" version="1.0.71" />
<package id="Microsoft.Xaml.Behaviors.WinUI.Managed" version="3.0.0" />
<package id="StrawberryPerl" version="5.28.0.1" />
<package id="StrawberryPerl" version="5.32.1.1" />
<package id="vswhere" version="3.1.7" />
<package id="WinUIEx" version="2.5.1" />
<package id="WinUIEx" version="2.9.0" />
<package id="Wix" version="5.0.2" />
</packages>

View File

@ -86,6 +86,9 @@ set(HEADERS
hcs.hpp
hcs_schema.h
helpers.hpp
interop.hpp
ExecutionContext.h
socket.hpp
hvsocket.hpp
INetworkingEngine.h
interop.hpp

View File

@ -167,16 +167,13 @@ wsl::windows::common::SvcComm::SvcComm()
};
wsl::shared::retry::RetryWithTimeout<void>(
[this]() {
THROW_IF_FAILED(CoCreateInstance(__uuidof(LxssUserSession), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&m_userSession)));
},
[this]() { m_userSession = wil::CoCreateInstance<LxssUserSession, ILxssUserSession>(CLSCTX_LOCAL_SERVER); },
std::chrono::seconds(1),
std::chrono::minutes(1),
retry_pred);
// Query client security interface.
wil::com_ptr_nothrow<IClientSecurity> clientSecurity;
THROW_IF_FAILED(m_userSession->QueryInterface(IID_PPV_ARGS(&clientSecurity)));
auto clientSecurity = m_userSession.query<IClientSecurity>();
// Get the current proxy blanket settings.
DWORD authnSvc, authzSvc, authnLvl, capabilities;

View File

@ -624,6 +624,11 @@ std::wstring wsl::windows::common::wslutil::DownloadFileImpl(
void wsl::windows::common::wslutil::EnforceFileLimit(LPCWSTR Path, size_t Limit, const std::function<bool(const std::filesystem::directory_entry&)>& pred)
{
if (Limit <= 0)
{
return;
}
std::map<std::filesystem::file_time_type, std::filesystem::path> files;
for (auto const& e : std::filesystem::directory_iterator{Path})
{
@ -633,7 +638,7 @@ void wsl::windows::common::wslutil::EnforceFileLimit(LPCWSTR Path, size_t Limit,
}
}
if (Limit < 0 || files.size() < Limit)
if (files.size() < Limit)
{
return;
}

View File

@ -79,6 +79,22 @@ void CoInitializeSecurity();
void ConfigureCrt();
/// <summary>
/// Creates a COM server with user impersonation.
/// </summary>
template <typename Interface>
wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ REFCLSID RefClsId, _In_ HANDLE UserToken)
{
auto revert = wil::impersonate_token(UserToken);
return wil::CoCreateInstance<Interface>(RefClsId, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
}
template <typename Class, typename Interface>
wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ HANDLE UserToken)
{
return CreateComServerAsUser<Interface>(__uuidof(Class), UserToken);
}
std::wstring ConstructPipePath(_In_ std::wstring_view PipeName);
GUID CreateV5Uuid(const GUID& namespaceGuid, const std::span<const std::byte> name);

View File

@ -77,7 +77,7 @@ namespace Windows { namespace Internal {
// Tell COM how to mask fatal exceptions.
if (ownProcess)
{
Microsoft::WRL::ComPtr<IGlobalOptions> pIGLB;
wil::com_ptr<IGlobalOptions> pIGLB;
RETURN_IF_FAILED(CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIGLB)));
RETURN_IF_FAILED(pIGLB->Set(COMGLB_EXCEPTION_HANDLING, TExceptionPolicy));
}
@ -294,7 +294,7 @@ namespace Windows { namespace Internal {
bool m_addedModuleReference = false;
// COM callback object to support unloading shared-process services
Microsoft::WRL::ComPtr<IContextCallback> m_icc;
wil::com_ptr<IContextCallback> m_icc;
// COM Server descriptor
ServerDescriptor m_serverDescriptor{};

View File

@ -12,6 +12,7 @@ set(SOURCES
BridgedNetworking.cpp
GnsPortTrackerChannel.cpp
GnsRpcServer.cpp
GuestDeviceManager.cpp
GuestTelemetryLogger.cpp
Lifetime.cpp
LxssConsoleManager.cpp
@ -40,6 +41,7 @@ set(HEADERS
BridgedNetworking.h
GnsPortTrackerChannel.h
GnsRpcServer.h
GuestDeviceManager.h
GuestTelemetryLogger.h
IMirroredNetworkManager.h
Lifetime.h

View File

@ -0,0 +1,149 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
#include "precomp.h"
#include "GuestDeviceManager.h"
#include "DeviceHostProxy.h"
GuestDeviceManager::GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId) :
m_machineId(machineId), m_deviceHostSupport(wil::MakeOrThrow<DeviceHostProxy>(machineId, runtimeId))
{
}
_Requires_lock_not_held_(m_lock)
GUID GuestDeviceManager::AddGuestDevice(
_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
{
auto guestDeviceLock = m_lock.lock_exclusive();
return AddHdvShareWithOptions(DeviceId, ImplementationClsid, AccessName, Options, Path, Flags, UserToken);
}
_Requires_lock_held_(m_lock)
GUID GuestDeviceManager::AddHdvShareWithOptions(
_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
{
wil::com_ptr<IPlan9FileSystem> server;
// Options are appended to the name with a semi-colon separator.
// "name;key1=value1;key2=value2"
// The AddSharePath implementation is responsible for separating them out and interpreting them.
std::wstring nameWithOptions{AccessName};
if (ARGUMENT_PRESENT(Options))
{
nameWithOptions += L";";
nameWithOptions += Options;
}
{
auto revert = wil::impersonate_token(UserToken);
server = GetRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag);
if (!server)
{
server = wil::CoCreateInstance<IPlan9FileSystem>(ImplementationClsid, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
AddRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag.c_str(), server);
}
THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), Path, Flags));
}
// This requires more privileges than the user may have, so impersonation is disabled.
return AddNewDevice(DeviceId, server, AccessName);
}
GUID GuestDeviceManager::AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag)
{
THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
return m_deviceHostSupport->AddNewDevice(deviceId, server, tag);
}
void GuestDeviceManager::AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server)
{
THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
m_deviceHostSupport->AddRemoteFileSystem(clsid, tag, server);
}
void GuestDeviceManager::AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken)
{
auto guestDeviceLock = m_lock.lock_exclusive();
auto objectLifetime = CreateSectionObjectRoot(Path, UserToken);
// For virtiofs hdv, the flags parameter has been overloaded. Flags are placed in the lower
// 16 bits, while the shared memory size in megabytes are placed in the upper 16 bits.
static constexpr auto VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT = 16;
UINT32 flags = (SizeMb << VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT);
WI_SetFlag(flags, VIRTIO_FS_FLAGS_TYPE_SECTIONS);
(void)AddHdvShareWithOptions(VIRTIO_VIRTIOFS_DEVICE_ID, ImplementationClsid, Tag, {}, objectLifetime.Path.c_str(), flags, UserToken);
m_objectDirectories.emplace_back(std::move(objectLifetime));
}
GuestDeviceManager::DirectoryObjectLifetime GuestDeviceManager::CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const
{
auto revert = wil::impersonate_token(UserToken);
DWORD sessionId;
DWORD bytesWritten;
THROW_LAST_ERROR_IF(!GetTokenInformation(GetCurrentThreadToken(), TokenSessionId, &sessionId, sizeof(sessionId), &bytesWritten));
// /Sessions/1/BaseNamedObjects/WSL/<VM ID>/<Relative Path>
std::wstringstream sectionPathBuilder;
sectionPathBuilder << L"\\Sessions\\" << sessionId << L"\\BaseNamedObjects" << L"\\WSL\\" << m_machineId << L"\\" << RelativeRootPath;
auto sectionPath = sectionPathBuilder.str();
UNICODE_STRING ntPath{};
OBJECT_ATTRIBUTES attributes{};
attributes.Length = sizeof(OBJECT_ATTRIBUTES);
attributes.ObjectName = &ntPath;
std::vector<wil::unique_handle> directoryHierarchy;
auto remainingPath = std::wstring_view(sectionPath.data(), sectionPath.length());
while (remainingPath.length() > 0)
{
// Find the next path substring, ignoring the root path backslash.
auto nextDir = remainingPath;
const auto separatorPos = nextDir.find(L"\\", remainingPath[0] == L'\\' ? 1 : 0);
if (separatorPos != std::wstring_view::npos)
{
nextDir = nextDir.substr(0, separatorPos);
remainingPath = remainingPath.substr(separatorPos + 1, std::wstring_view::npos);
// Skip concurrent backslashes.
while (remainingPath.length() > 0 && remainingPath[0] == L'\\')
{
remainingPath = remainingPath.substr(1, std::wstring_view::npos);
}
}
else
{
remainingPath = remainingPath.substr(remainingPath.length(), std::wstring_view::npos);
}
attributes.RootDirectory = directoryHierarchy.size() > 0 ? directoryHierarchy.back().get() : nullptr;
ntPath.Buffer = const_cast<PWCH>(nextDir.data());
ntPath.Length = sizeof(WCHAR) * gsl::narrow_cast<USHORT>(nextDir.length());
ntPath.MaximumLength = ntPath.Length;
wil::unique_handle nextHandle;
NTSTATUS status = ZwCreateDirectoryObject(&nextHandle, DIRECTORY_ALL_ACCESS, &attributes);
if (status == STATUS_OBJECT_NAME_COLLISION)
{
status = NtOpenDirectoryObject(&nextHandle, MAXIMUM_ALLOWED, &attributes);
}
THROW_IF_NTSTATUS_FAILED(status);
directoryHierarchy.emplace_back(std::move(nextHandle));
}
return {std::move(sectionPath), std::move(directoryHierarchy)};
}
wil::com_ptr<IPlan9FileSystem> GuestDeviceManager::GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag)
{
THROW_HR_IF(E_NOT_VALID_STATE, !m_deviceHostSupport);
return m_deviceHostSupport->GetRemoteFileSystem(clsid, tag);
}
void GuestDeviceManager::Shutdown()
try
{
if (m_deviceHostSupport)
{
m_deviceHostSupport->Shutdown();
}
}
CATCH_LOG()

View File

@ -0,0 +1,72 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
#pragma once
#include "DeviceHostProxy.h"
// Flags for virtiofs vdev device creation.
#define VIRTIO_FS_FLAGS_TYPE_FILES 0x8000
#define VIRTIO_FS_FLAGS_TYPE_SECTIONS 0x4000
// {872270E1-A899-4AF6-B454-7193634435AD}
DEFINE_GUID(VIRTIO_VIRTIOFS_DEVICE_ID, 0x872270E1, 0xA899, 0x4AF6, 0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD);
// {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
DEFINE_GUID(VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xe2, 0xe5, 0x78, 0x7a, 0xbc, 0xf6, 0xc2);
inline const std::wstring c_defaultDeviceTag = L"default";
//
// Provides synchronized access to guest device operations.
//
class GuestDeviceManager
{
public:
GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId);
_Requires_lock_not_held_(m_lock)
GUID AddGuestDevice(
_In_ const GUID& DeviceId,
_In_ const GUID& ImplementationClsid,
_In_ PCWSTR AccessName,
_In_opt_ PCWSTR Options,
_In_ PCWSTR Path,
_In_ UINT32 Flags,
_In_ HANDLE UserToken);
GUID AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag);
void AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server);
void AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken);
wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag);
void Shutdown();
private:
_Requires_lock_held_(m_lock)
GUID AddHdvShareWithOptions(
_In_ const GUID& DeviceId,
_In_ const GUID& ImplementationClsid,
_In_ PCWSTR AccessName,
_In_opt_ PCWSTR Options,
_In_ PCWSTR Path,
_In_ UINT32 Flags,
_In_ HANDLE UserToken);
struct DirectoryObjectLifetime
{
std::wstring Path;
// Directory objects are temporary, even if they have children, so need to keep
// any created handles open in order for the directory to remain accessible.
std::vector<wil::unique_handle> HierarchyLifetimes;
};
DirectoryObjectLifetime CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const;
wil::srwlock m_lock;
std::wstring m_machineId;
wil::com_ptr<DeviceHostProxy> m_deviceHostSupport;
_Guarded_by_(m_lock) std::vector<DirectoryObjectLifetime> m_objectDirectories;
};

View File

@ -335,7 +335,7 @@ const std::wstring LxssNetworkingFirewall::s_FriendlyNamePrefix(L"WSLRULE_177744
LxssNetworkingFirewall::LxssNetworkingFirewall()
{
THROW_IF_FAILED(::CoCreateInstance(__uuidof(NetFwPolicy2), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_firewall)));
m_firewall = wil::CoCreateInstance<NetFwPolicy2, INetFwPolicy2>(CLSCTX_INPROC_SERVER);
}
void LxssNetworkingFirewall::CopyPartialArray(SAFEARRAY* Destination, SAFEARRAY* Source, ULONG DestinationIndexStart, ULONG SourceIndexStart, ULONG ElementsToCopy)
@ -388,8 +388,7 @@ void LxssNetworkingFirewall::CopyPartialArray(SAFEARRAY* Destination, SAFEARRAY*
std::wstring LxssNetworkingFirewall::AddPortRule(const IP_ADDRESS_PREFIX& Address) const
{
Microsoft::WRL::ComPtr<INetFwRule> newRule;
THROW_IF_FAILED(::CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&newRule)));
auto newRule = wil::CoCreateInstance<NetFwRule, INetFwRule>(CLSCTX_INPROC_SERVER);
// Open a port via the firewall by creating a rule that specifies the local
// address and the local port to allow. Currently this rule only applies to
@ -412,9 +411,9 @@ std::wstring LxssNetworkingFirewall::AddPortRule(const IP_ADDRESS_PREFIX& Addres
THROW_IF_FAILED(newRule->put_Description(s_DefaultRuleDescription.get()));
THROW_IF_FAILED(newRule->put_Enabled(VARIANT_TRUE));
// Add the rule to the existing set.
Microsoft::WRL::ComPtr<INetFwRules> rules;
wil::com_ptr<INetFwRules> rules;
THROW_IF_FAILED(m_firewall->get_Rules(&rules));
THROW_IF_FAILED(rules->Add(newRule.Get()));
THROW_IF_FAILED(rules->Add(newRule.get()));
// Return the unique rule name to the caller.
return generatedName;
}
@ -423,12 +422,11 @@ void LxssNetworkingFirewall::CleanupRemnants()
{
auto firewall = std::make_shared<LxssNetworkingFirewall>();
THROW_HR_IF(E_OUTOFMEMORY, !firewall);
Microsoft::WRL::ComPtr<INetFwRules> rules;
wil::com_ptr<INetFwRules> rules;
THROW_IF_FAILED(firewall->m_firewall->get_Rules(&rules));
Microsoft::WRL::ComPtr<IUnknown> enumInterface;
THROW_IF_FAILED(rules->get__NewEnum(enumInterface.GetAddressOf()));
Microsoft::WRL::ComPtr<IEnumVARIANT> rulesEnum;
THROW_IF_FAILED(enumInterface.As(&rulesEnum));
wil::com_ptr<IUnknown> enumInterface;
THROW_IF_FAILED(rules->get__NewEnum(enumInterface.addressof()));
auto rulesEnum = enumInterface.query<IEnumVARIANT>();
// Find any rules with the unique WSL prefix and destroy them.
for (;;)
{
@ -440,7 +438,7 @@ void LxssNetworkingFirewall::CleanupRemnants()
break;
}
Microsoft::WRL::ComPtr<INetFwRule> nextRule;
wil::com_ptr<INetFwRule> nextRule;
THROW_IF_FAILED(next.pdispVal->QueryInterface(IID_PPV_ARGS(&nextRule)));
wil::unique_bstr nextRuleName;
THROW_IF_FAILED(nextRule->get_Name(nextRuleName.addressof()));
@ -558,7 +556,7 @@ void LxssNetworkingFirewall::RemoveExcludedAdapter(const std::wstring& AdapterNa
void LxssNetworkingFirewall::RemovePortRule(const std::wstring& RuleName) const
{
Microsoft::WRL::ComPtr<INetFwRules> rules;
wil::com_ptr<INetFwRules> rules;
THROW_IF_FAILED(m_firewall->get_Rules(&rules));
THROW_IF_FAILED(rules->Remove(wil::make_bstr_failfast(RuleName.c_str()).get()));
}
@ -572,8 +570,7 @@ LxssNetworkingFirewallPort::LxssNetworkingFirewallPort(const std::shared_ptr<Lxs
return;
}
LxssNetworkingFirewallPort::LxssNetworkingFirewallPort(
const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const Microsoft::WRL::ComPtr<INetFwRule>& Existing) :
LxssNetworkingFirewallPort::LxssNetworkingFirewallPort(const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const wil::com_ptr<INetFwRule>& Existing) :
m_firewall(Firewall)
{
wil::unique_bstr ruleName;

View File

@ -262,7 +262,7 @@ private:
/// <summary>
/// COM firewall instance.
/// </summary>
Microsoft::WRL::ComPtr<INetFwPolicy2> m_firewall;
wil::com_ptr<INetFwPolicy2> m_firewall;
/// <summary>
/// Lock to protect class members.
@ -295,7 +295,7 @@ public:
/// <summary>
/// Constructor to take ownership of an existing rule.
/// </summary>
LxssNetworkingFirewallPort(const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const Microsoft::WRL::ComPtr<INetFwRule>& Existing);
LxssNetworkingFirewallPort(const std::shared_ptr<LxssNetworkingFirewall>& Firewall, const wil::com_ptr<INetFwRule>& Existing);
/// <summary>
/// Destructor.

View File

@ -2674,8 +2674,7 @@ try
THROW_IF_FAILED(shellLink->SetArguments(commandLine.c_str()));
THROW_IF_FAILED(shellLink->SetIconLocation(ShortcutIcon, 0));
Microsoft::WRL::ComPtr<IPersistFile> storage;
THROW_IF_FAILED(shellLink->QueryInterface(IID_IPersistFile, &storage));
auto storage = shellLink.query<IPersistFile>();
THROW_IF_FAILED(storage->Save(shortcutPath.c_str(), true));
registration.Write(Property::ShortcutPath, shortcutPath.c_str());

View File

@ -2,6 +2,7 @@
#include "precomp.h"
#include "VirtioNetworking.h"
#include "GuestDeviceManager.h"
#include "Stringify.h"
#include "stringshared.h"
@ -12,34 +13,18 @@ using wsl::core::VirtioNetworking;
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
VirtioNetworking::VirtioNetworking(GnsChannel&& gnsChannel, const Config& config) :
m_gnsChannel(std::move(gnsChannel)), m_config(config)
VirtioNetworking::VirtioNetworking(
GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
m_guestDeviceManager(std::move(guestDeviceManager)),
m_userToken(std::move(userToken)),
m_gnsChannel(std::move(gnsChannel)),
m_enableLocalhostRelay(enableLocalhostRelay)
{
}
VirtioNetworking& VirtioNetworking::OnAddGuestDevice(const AddGuestDeviceRoutine& addGuestDeviceRoutine)
{
m_addGuestDeviceRoutine = addGuestDeviceRoutine;
return *this;
}
VirtioNetworking& VirtioNetworking::OnModifyOpenPorts(const ModifyOpenPortsCallback& modifyOpenPortsCallback)
{
m_modifyOpenPortsCallback = modifyOpenPortsCallback;
return *this;
}
VirtioNetworking& VirtioNetworking::OnGuestInterfaceStateChanged(const GuestInterfaceStateChangeCallback& guestInterfaceStateChangedCallback)
{
m_guestInterfaceStateChangeCallback = guestInterfaceStateChangedCallback;
return *this;
}
void VirtioNetworking::Initialize()
try
{
THROW_HR_IF(E_NOT_SET, !m_addGuestDeviceRoutine || !m_modifyOpenPortsCallback || !m_guestInterfaceStateChangeCallback);
m_networkSettings = GetHostEndpointSettings();
// TODO: Determine gateway MAC address
@ -83,11 +68,12 @@ try
device_options << L"nameservers=" << dns_servers;
}
// Add virtio net adapter to guest
m_adapterId = (*m_addGuestDeviceRoutine)(c_virtioNetworkClsid, c_virtioNetworkDeviceId, L"eth0", device_options.str().c_str());
auto lock = m_lock.lock_exclusive();
// Add virtio net adapter to guest
m_adapterId = m_guestDeviceManager->AddGuestDevice(
c_virtioNetworkDeviceId, c_virtioNetworkClsid, L"eth0", nullptr, device_options.str().c_str(), 0, m_userToken.get());
hns::HNSEndpoint endpointProperties;
endpointProperties.ID = m_adapterId;
endpointProperties.IPAddress = m_networkSettings->PreferredIpAddress.AddressString;
@ -121,7 +107,7 @@ try
UpdateDns(std::move(dnsSettings));
}
if (m_config.EnableLocalhostRelay)
if (m_enableLocalhostRelay)
{
SetupLoopbackDevice();
}
@ -132,8 +118,14 @@ CATCH_LOG()
void VirtioNetworking::SetupLoopbackDevice()
{
m_localhostAdapterId = (*m_addGuestDeviceRoutine)(
c_virtioNetworkClsid, c_virtioNetworkDeviceId, c_loopbackDeviceName, L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55");
m_localhostAdapterId = m_guestDeviceManager->AddGuestDevice(
c_virtioNetworkDeviceId,
c_virtioNetworkClsid,
c_loopbackDeviceName,
nullptr,
L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55",
0,
m_userToken.get());
hns::HNSEndpoint endpointProperties;
endpointProperties.ID = m_localhostAdapterId;
@ -162,7 +154,7 @@ void VirtioNetworking::StartPortTracker(wil::unique_socket&& socket)
m_gnsPortTrackerChannel.emplace(
std::move(socket),
[&](const SOCKADDR_INET& addr, int protocol, bool allocate) { return HandlePortNotification(addr, protocol, allocate); },
[&](_In_ const std::string& interfaceName, _In_ bool up) { (*m_guestInterfaceStateChangeCallback)(interfaceName, up); });
[](const std::string&, bool) {}); // TODO: reconsider if InterfaceStateCallback is needed.
}
HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int protocol, bool allocate) const noexcept
@ -181,7 +173,7 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int
}
}
if (m_config.EnableLocalhostRelay && (unspecified || loopback))
if (m_enableLocalhostRelay && (unspecified || loopback))
{
SOCKADDR_INET localAddr = addr;
if (!loopback)
@ -196,21 +188,65 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int
localAddr.Ipv6.sin6_port = addr.Ipv6.sin6_port;
}
}
result = (*m_modifyOpenPortsCallback)(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
result = ModifyOpenPorts(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
LOG_HR_IF_MSG(E_FAIL, result != S_OK, "Failure adding localhost relay port %d", localAddr.Ipv4.sin_port);
}
if (!loopback)
{
const int localResult = (*m_modifyOpenPortsCallback)(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
const int localResult = ModifyOpenPorts(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
LOG_HR_IF_MSG(E_FAIL, localResult != S_OK, "Failure adding relay port %d", addr.Ipv4.sin_port);
if (result == 0)
{
result = localResult;
}
}
return result;
}
int VirtioNetworking::ModifyOpenPorts(_In_ const GUID& clsid, _In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const
{
if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
{
LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", protocol);
return 0;
}
else if (addr.si_family == AF_INET6)
{
// The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
// IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
// be handled as a separate callback to this same code.
return 0;
}
auto lock = m_lock.lock_exclusive();
const auto server = m_guestDeviceManager->GetRemoteFileSystem(clsid, c_defaultDeviceTag);
if (server)
{
std::wstring portString = std::format(L"tag={};port_number={}", tag, addr.Ipv4.sin_port);
if (protocol == IPPROTO_UDP)
{
portString += L";udp";
}
if (!isOpen)
{
portString += L";allocate=false";
}
else
{
wchar_t addrStr[16]; // "000.000.000.000" + null terminator
RtlIpv4AddressToStringW(&addr.Ipv4.sin_addr, addrStr);
portString += std::format(L";listen_addr={}", addrStr);
}
LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
}
return 0;
}
void NETIOAPI_API_ VirtioNetworking::OnNetworkConnectivityChange(PVOID context, NL_NETWORK_CONNECTIVITY_HINT hint)
{
static_cast<VirtioNetworking*>(context)->RefreshGuestConnection(hint);

View File

@ -6,23 +6,16 @@
#include "GnsChannel.h"
#include "WslCoreHostDnsInfo.h"
#include "GnsPortTrackerChannel.h"
#include "GuestDeviceManager.h"
namespace wsl::core {
using AddGuestDeviceRoutine = std::function<GUID(const GUID& clsid, const GUID& deviceId, PCWSTR tag, PCWSTR options)>;
using ModifyOpenPortsCallback = std::function<int(const GUID& clsid, PCWSTR tag, const SOCKADDR_INET& addr, int protocol, bool isOpen)>;
using GuestInterfaceStateChangeCallback = std::function<void(const std::string& name, bool isUp)>;
class VirtioNetworking : public INetworkingEngine
{
public:
VirtioNetworking(GnsChannel&& gnsChannel, const Config& config);
VirtioNetworking(GnsChannel&& gnsChannel, bool enableLocalhostRelay, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
~VirtioNetworking() = default;
VirtioNetworking& OnAddGuestDevice(const AddGuestDeviceRoutine& addGuestDeviceRoutine);
VirtioNetworking& OnModifyOpenPorts(const ModifyOpenPortsCallback& modifyOpenPortsCallback);
VirtioNetworking& OnGuestInterfaceStateChanged(const GuestInterfaceStateChangeCallback& guestInterfaceStateChangedCallback);
// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
VirtioNetworking(const VirtioNetworking&) = delete;
VirtioNetworking(VirtioNetworking&&) = delete;
@ -42,6 +35,7 @@ private:
static std::optional<ULONGLONG> FindVirtioInterfaceLuid(const SOCKADDR_INET& virtioAddress, const NL_NETWORK_CONNECTIVITY_HINT& currentConnectivityHint);
HRESULT HandlePortNotification(const SOCKADDR_INET& addr, int protocol, bool allocate) const noexcept;
int ModifyOpenPorts(_In_ const GUID& clsid, _In_ PCWSTR tag, _In_ const SOCKADDR_INET& addr, _In_ int protocol, _In_ bool isOpen) const;
void RefreshGuestConnection(NL_NETWORK_CONNECTIVITY_HINT hint) noexcept;
void SetupLoopbackDevice();
void UpdateDns(wsl::shared::hns::DNS&& dnsSettings);
@ -49,17 +43,14 @@ private:
mutable wil::srwlock m_lock;
std::optional<AddGuestDeviceRoutine> m_addGuestDeviceRoutine;
std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
wil::shared_handle m_userToken;
GnsChannel m_gnsChannel;
std::optional<GnsPortTrackerChannel> m_gnsPortTrackerChannel;
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
const Config& m_config;
bool m_enableLocalhostRelay;
GUID m_localhostAdapterId;
GUID m_adapterId;
std::optional<NL_NETWORK_CONNECTIVITY_LEVEL_HINT> m_connectivityLevel;
std::optional<NL_NETWORK_CONNECTIVITY_COST_HINT> m_connectivityCost;
std::optional<ModifyOpenPortsCallback> m_modifyOpenPortsCallback;
std::optional<GuestInterfaceStateChangeCallback> m_guestInterfaceStateChangeCallback;
std::optional<ULONGLONG> m_interfaceLuid;
ULONG m_networkMtu = 0;

View File

@ -39,27 +39,16 @@ using namespace std::string_literals;
// Start of unaddressable memory if guest only supports the minimum 36-bit addressing.
#define MAX_36_BIT_PAGE_IN_MB (0x1000000000 / _1MB)
// This device type is implemented by the external virtiofs vdev.
// {872270E1-A899-4AF6-B454-7193634435AD}
DEFINE_GUID(VIRTIO_VIRTIOFS_DEVICE_ID, 0x872270E1, 0xA899, 0x4AF6, 0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD);
// This device type is implemented by the external virtio-pmem vdev.
// {EDBB24BB-5E19-40F4-8A0F-8224313064FD}
DEFINE_GUID(VIRTIO_PMEM_DEVICE_ID, 0xEDBB24BB, 0x5E19, 0x40F4, 0x8A, 0x0F, 0x82, 0x24, 0x31, 0x30, 0x64, 0xFD);
// Flags for virtiofs vdev device creation.
#define VIRTIO_FS_FLAGS_TYPE_FILES 0x8000
#define VIRTIO_FS_FLAGS_TYPE_SECTIONS 0x4000
#define WSLG_SHARED_MEMORY_SIZE_MB 8192
#define PAGE_SIZE 0x1000
static constexpr size_t c_bootEntropy = 0x1000;
static constexpr auto c_localDevicesKey = L"SOFTWARE\\Microsoft\\Terminal Server Client\\LocalDevices";
// {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
static constexpr GUID c_pmemClassId = {0xABB755FC, 0x1B86, 0x4255, {0x83, 0xe2, 0xe5, 0x78, 0x7a, 0xbc, 0xf6, 0xc2}};
#define LXSS_ENABLE_GUI_APPS() (m_vmConfig.EnableGuiApps && (m_systemDistroDeviceId != ULONG_MAX))
using namespace wsl::windows::common;
@ -70,8 +59,6 @@ using wsl::shared::Localization;
using wsl::windows::common::Context;
using wsl::windows::common::ExecutionContext;
const std::wstring WslCoreVm::c_defaultTag = L"default"s;
namespace {
INT64
RequiredExtraMmioSpaceForPmemFileInMb(_In_ PCWSTR FilePath)
@ -335,7 +322,8 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
m_runtimeId = wsl::windows::common::hcs::GetRuntimeId(m_system.get());
WI_ASSERT(IsEqualGUID(VmId, m_runtimeId));
m_deviceHostSupport = wil::MakeOrThrow<DeviceHostProxy>(m_machineId, m_runtimeId);
// Initialize the guest device manager.
m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_machineId, m_runtimeId);
// Create a socket listening for connections from mini_init.
m_listenSocket = wsl::windows::common::hvsocket::Listen(m_runtimeId, LX_INIT_UTILITY_VM_INIT_PORT);
@ -462,7 +450,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
break;
case LxMiniInitMountDeviceTypePmem:
m_systemDistroDeviceId = MountFileAsPersistentMemory(c_pmemClassId, m_vmConfig.SystemDistroPath.c_str(), true);
m_systemDistroDeviceId = MountFileAsPersistentMemory(m_vmConfig.SystemDistroPath.c_str(), true);
break;
default:
@ -600,55 +588,8 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
}
else if (m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
{
auto virtioNetworkingEngine = std::make_unique<wsl::core::VirtioNetworking>(std::move(gnsChannel), m_vmConfig);
virtioNetworkingEngine->OnAddGuestDevice([&](const GUID& Clsid, const GUID& DeviceId, PCWSTR Tag, PCWSTR Options) {
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
return AddHdvShareWithOptions(DeviceId, Clsid, Tag, {}, Options, 0, m_userToken.get());
});
virtioNetworkingEngine->OnModifyOpenPorts([&](const GUID& Clsid, PCWSTR Tag, const SOCKADDR_INET& addr, int protocol, bool isOpen) {
if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
{
LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", protocol);
return 0;
}
else if (addr.si_family == AF_INET6)
{
// The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
// IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
// be handled as a separate callback to this same code.
return 0;
}
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
const auto server = m_deviceHostSupport->GetRemoteFileSystem(Clsid, c_defaultTag);
if (server)
{
std::wstring portString(L"tag=");
portString += Tag;
portString += L";port_number=";
portString += std::to_wstring(addr.Ipv4.sin_port);
if (protocol == IPPROTO_UDP)
{
portString += L";udp";
}
if (!isOpen)
{
portString += L";allocate=false";
}
else
{
std::wstring addrStr(L"000.000.000.000\0");
RtlIpv4AddressToStringW(&addr.Ipv4.sin_addr, addrStr.data());
portString += L";listen_addr=";
portString += addrStr;
}
LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
}
return 0;
});
virtioNetworkingEngine->OnGuestInterfaceStateChanged([&](const std::string& name, bool isUp) {});
m_networkingEngine.reset(virtioNetworkingEngine.release());
m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
std::move(gnsChannel), m_vmConfig.EnableLocalhostRelay, m_guestDeviceManager, m_userToken);
}
else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
{
@ -831,9 +772,9 @@ WslCoreVm::~WslCoreVm() noexcept
}
// Shutdown virtio device hosts.
if (m_deviceHostSupport)
if (m_guestDeviceManager)
{
m_deviceHostSupport->Shutdown();
m_guestDeviceManager->Shutdown();
}
// Call RevokeVmAccess on each VHD that was added to the utility VM. This
@ -956,7 +897,7 @@ void WslCoreVm::AddPlan9Share(
if (m_vmConfig.EnableVirtio9p)
{
server = m_deviceHostSupport->GetRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag);
server = m_guestDeviceManager->GetRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag);
}
else
{
@ -969,10 +910,10 @@ void WslCoreVm::AddPlan9Share(
if (!server)
{
server = CreateComServerAsUser<p9fs::Plan9FileSystem, IPlan9FileSystem>(UserToken);
server = wsl::windows::common::wslutil::CreateComServerAsUser<p9fs::Plan9FileSystem, IPlan9FileSystem>(UserToken);
if (m_vmConfig.EnableVirtio9p)
{
m_deviceHostSupport->AddRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag, server);
m_guestDeviceManager->AddRemoteFileSystem(__uuidof(p9fs::Plan9FileSystem), VirtIoTag, server);
// Start with one device to handle the first mount request. After
// each mount, the Plan9 file-system will request additional
@ -1000,66 +941,10 @@ void WslCoreVm::AddPlan9Share(
if (addNewDevice)
{
// This requires more privileges than the user may have, so impersonation is disabled.
(void)m_deviceHostSupport->AddNewDevice(VIRTIO_PLAN9_DEVICE_ID, server, VirtIoTag);
(void)m_guestDeviceManager->AddNewDevice(VIRTIO_PLAN9_DEVICE_ID, server, VirtIoTag);
}
}
WslCoreVm::DirectoryObjectLifetime WslCoreVm::CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const
{
auto revert = wil::impersonate_token(UserToken);
DWORD sessionId;
DWORD bytesWritten;
THROW_LAST_ERROR_IF(!GetTokenInformation(GetCurrentThreadToken(), TokenSessionId, &sessionId, sizeof(sessionId), &bytesWritten));
// /Sessions/1/BaseNamedObjects/WSL/<VM ID>/<Relative Path>
std::wstringstream sectionPathBuilder;
sectionPathBuilder << L"\\Sessions\\" << sessionId << L"\\BaseNamedObjects" << L"\\WSL\\" << m_machineId << L"\\" << RelativeRootPath;
auto sectionPath = sectionPathBuilder.str();
UNICODE_STRING ntPath{};
OBJECT_ATTRIBUTES attributes{};
attributes.Length = sizeof(OBJECT_ATTRIBUTES);
attributes.ObjectName = &ntPath;
std::vector<wil::unique_handle> directoryHierarchy;
auto remainingPath = std::wstring_view(sectionPath.data(), sectionPath.length());
while (remainingPath.length() > 0)
{
// Find the next path substring, ignoring the root path backslash.
auto nextDir = remainingPath;
const auto separatorPos = nextDir.find(L"\\", remainingPath[0] == L'\\' ? 1 : 0);
if (separatorPos != std::wstring_view::npos)
{
nextDir = nextDir.substr(0, separatorPos);
remainingPath = remainingPath.substr(separatorPos + 1, std::wstring_view::npos);
// Skip concurrent backslashes.
while (remainingPath.length() > 0 && remainingPath[0] == L'\\')
{
remainingPath = remainingPath.substr(1, std::wstring_view::npos);
}
}
else
{
remainingPath = remainingPath.substr(remainingPath.length(), std::wstring_view::npos);
}
attributes.RootDirectory = directoryHierarchy.size() > 0 ? directoryHierarchy.back().get() : nullptr;
ntPath.Buffer = const_cast<PWCH>(nextDir.data());
ntPath.Length = sizeof(WCHAR) * gsl::narrow_cast<USHORT>(nextDir.length());
ntPath.MaximumLength = ntPath.Length;
wil::unique_handle nextHandle;
NTSTATUS status = ZwCreateDirectoryObject(&nextHandle, DIRECTORY_ALL_ACCESS, &attributes);
if (status == STATUS_OBJECT_NAME_COLLISION)
{
status = NtOpenDirectoryObject(&nextHandle, MAXIMUM_ALLOWED, &attributes);
}
THROW_IF_NTSTATUS_FAILED(status);
directoryHierarchy.emplace_back(std::move(nextHandle));
}
return {std::move(sectionPath), std::move(directoryHierarchy)};
}
ULONG WslCoreVm::AttachDisk(_In_ PCWSTR Disk, _In_ DiskType Type, _In_ std::optional<ULONG> Lun, _In_ bool IsUserDisk, _In_ HANDLE UserToken)
{
auto lock = m_lock.lock_exclusive();
@ -1868,7 +1753,8 @@ void WslCoreVm::InitializeGuest()
{
try
{
MountSharedMemoryDevice(c_virtiofsClassId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB);
m_guestDeviceManager->AddSharedMemoryDevice(
c_virtiofsClassId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
m_sharedMemoryRoot = std::format(L"WSL\\{}\\wslg", m_machineId);
}
CATCH_LOG()
@ -1967,7 +1853,7 @@ bool WslCoreVm::InitializeDrvFsLockHeld(_In_ HANDLE UserToken)
{
// Before checking whether DrvFs is already initialized, make sure any existing Plan 9 servers
// are usable.
VerifyDrvFsServers();
VerifyPlan9Servers();
const auto elevated = wsl::windows::common::security::IsTokenElevated(UserToken);
if (elevated)
@ -1999,6 +1885,12 @@ bool WslCoreVm::IsDnsTunnelingSupported() const
return SUCCEEDED_LOG(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
}
bool WslCoreVm::IsVhdAttached(_In_ PCWSTR VhdPath)
{
auto lock = m_lock.lock_exclusive();
return m_attachedDisks.contains({DiskType::VHD, VhdPath});
}
WslCoreVm::DiskMountResult WslCoreVm::MountDisk(
_In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options)
{
@ -2098,33 +1990,8 @@ void WslCoreVm::MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR Gue
ResultMessage.Result);
}
void WslCoreVm::MountSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb)
{
if (!m_vmConfig.EnableVirtio)
{
return;
}
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
MountSharedMemoryDeviceLockHeld(ImplementationClsid, Tag, Path, SizeMb);
}
_Requires_lock_held_(m_guestDeviceLock)
void WslCoreVm::MountSharedMemoryDeviceLockHeld(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb)
{
auto objectLifetime = CreateSectionObjectRoot(Path, m_userToken.get());
// For virtiofs hdv, the flags parameter has been overloaded. Flags are placed in the lower
// 16 bits, while the shared memory size in megabytes are placed in the upper 16 bits.
static constexpr auto VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT = 16;
UINT32 flags = (SizeMb << VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT);
WI_SetFlag(flags, VIRTIO_FS_FLAGS_TYPE_SECTIONS);
(void)AddHdvShare(VIRTIO_VIRTIOFS_DEVICE_ID, ImplementationClsid, Tag, objectLifetime.Path.c_str(), flags, m_userToken.get());
m_objectDirectories.emplace_back(std::move(objectLifetime));
}
ULONG
WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In_ PCWSTR FilePath, _In_ bool ReadOnly)
WslCoreVm::MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly)
{
hcs::Plan9ShareFlags flags{};
@ -2146,7 +2013,7 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In
// a symlink that points to a path like:
// /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0004:00/VMBUS:00/<GUID>/pcicceb:00//cceb:00:00.0/virtio1/ndbus0/region0/namespace0.0/block/pmem0
// Notice the GUID in the middle of that path. That GUID is the instance ID, which is randomly
// generated by AddHdvShare. So once we find a path with the instance ID, we know that
// generated by AddGuestDevice. So once we find a path with the instance ID, we know that
// eventually /dev/pmemX will appear in the guest.
auto persistentMemoryLock = m_persistentMemoryLock.lock_exclusive();
@ -2157,8 +2024,8 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In
// added as part of VM creation and therefore any failure will result in VM termination
// (in which case there's no need to remove the device).
{
auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
(void)AddHdvShare(VIRTIO_PMEM_DEVICE_ID, ImplementationClsid, L"", FilePath, static_cast<UINT32>(flags), m_userToken.get());
(void)m_guestDeviceManager->AddGuestDevice(
VIRTIO_PMEM_DEVICE_ID, VIRTIO_PMEM_CLASS_ID, L"", nullptr, FilePath, static_cast<UINT32>(flags), m_userToken.get());
}
// Wait for the pmem device to appear in the VM at /dev/pmemX. Guess the value of X given the
@ -2207,56 +2074,6 @@ void WslCoreVm::WaitForPmemDeviceInVm(_In_ ULONG PmemId)
}
}
_Requires_lock_held_(m_guestDeviceLock)
GUID WslCoreVm::AddHdvShareWithOptions(
_In_ const GUID& DeviceId,
_In_ const GUID& ImplementationClsid,
_In_ std::wstring_view AccessName,
_In_ std::wstring_view Options,
_In_ std::wstring_view Path,
_In_ UINT32 Flags,
_In_ HANDLE UserToken)
{
wil::com_ptr<IPlan9FileSystem> server;
THROW_HR_IF(E_NOTIMPL, !m_vmConfig.EnableVirtio);
// Options are appended to the name with a semi-colon separator.
// "name;key1=value1;key2=value2"
// The AddSharePath implementation is responsible for separating them out and interpreting them.
std::wstring nameWithOptions{AccessName};
if (!Options.empty())
{
nameWithOptions += L";";
nameWithOptions += Options;
}
{
auto revert = wil::impersonate_token(UserToken);
server = m_deviceHostSupport->GetRemoteFileSystem(ImplementationClsid, c_defaultTag);
if (!server)
{
server = CreateComServerAsUser<IPlan9FileSystem>(ImplementationClsid, UserToken);
m_deviceHostSupport->AddRemoteFileSystem(ImplementationClsid, c_defaultTag, server);
}
const std::wstring SharePath(Path);
THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), SharePath.c_str(), Flags));
}
// This requires more privileges than the user may have, so impersonation is disabled.
const std::wstring VirtioTag(AccessName);
return m_deviceHostSupport->AddNewDevice(DeviceId, server, VirtioTag.c_str());
}
_Requires_lock_held_(m_guestDeviceLock)
GUID WslCoreVm::AddHdvShare(
_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
{
return AddHdvShareWithOptions(DeviceId, ImplementationClsid, AccessName, {}, Path, Flags, UserToken);
}
_Requires_lock_held_(m_guestDeviceLock)
std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken)
{
@ -2289,8 +2106,14 @@ std::wstring WslCoreVm::AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_
tag += std::to_wstring(m_virtioFsShares.size());
WI_ASSERT(!FindVirtioFsShare(tag.c_str(), Admin));
(void)AddHdvShareWithOptions(
VIRTIO_VIRTIOFS_DEVICE_ID, Admin ? c_virtiofsAdminClassId : c_virtiofsClassId, tag, key.OptionsString(), sharePath, VIRTIO_FS_FLAGS_TYPE_FILES, UserToken);
(void)m_guestDeviceManager->AddGuestDevice(
VIRTIO_VIRTIOFS_DEVICE_ID,
Admin ? c_virtiofsAdminClassId : c_virtiofsClassId,
tag.c_str(),
key.OptionsString().c_str(),
sharePath.c_str(),
VIRTIO_FS_FLAGS_TYPE_FILES,
UserToken);
m_virtioFsShares.emplace(std::move(key), tag);
created = true;
@ -2640,7 +2463,7 @@ std::pair<int, LX_MINI_MOUNT_STEP> WslCoreVm::UnmountVolume(_In_ const AttachedD
}
_Requires_lock_held_(m_guestDeviceLock)
void WslCoreVm::VerifyDrvFsServers()
void WslCoreVm::VerifyPlan9Servers()
{
for (auto it = m_plan9Servers.begin(); it != m_plan9Servers.end();)
{
@ -2810,12 +2633,6 @@ LX_INIT_DRVFS_MOUNT WslCoreVm::s_InitializeDrvFs(_Inout_ WslCoreVm* VmContext, _
}
}
bool WslCoreVm::IsVhdAttached(_In_ PCWSTR VhdPath)
{
auto lock = m_lock.lock_exclusive();
return m_attachedDisks.contains({DiskType::VHD, VhdPath});
}
void CALLBACK WslCoreVm::s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context)
try
{

View File

@ -29,6 +29,7 @@ Abstract:
#include "INetworkingEngine.h"
#include "SocketChannel.h"
#include "DeviceHostProxy.h"
#include "GuestDeviceManager.h"
#define UTILITY_VM_SHUTDOWN_TIMEOUT (30 * 1000)
#define UTILITY_VM_TERMINATE_TIMEOUT (30 * 1000)
@ -114,10 +115,8 @@ public:
ReadOnly = 0x1
};
void MountSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb);
ULONG
MountFileAsPersistentMemory(_In_ const GUID& ImplementationClsid, _In_ PCWSTR FilePath, _In_ bool ReadOnly);
MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly);
void MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR GuestPath, _In_ bool ReadOnly, _In_ LPCWSTR Name);
@ -129,7 +128,7 @@ public:
void SaveAttachedDisksState();
_Requires_lock_held_(m_guestDeviceLock)
void VerifyDrvFsServers();
void VerifyPlan9Servers();
enum DiskStateFlags
{
@ -166,14 +165,6 @@ private:
DiskStateFlags Flags;
};
struct DirectoryObjectLifetime
{
std::wstring Path;
// Directory objects are temporary, even if they have children, so need to keep
// any created handles open in order for the directory to remain accessible.
std::vector<wil::unique_handle> HierarchyLifetimes;
};
struct VirtioFsShare
{
VirtioFsShare(PCWSTR Path, PCWSTR Options, bool Admin);
@ -196,19 +187,6 @@ private:
_Requires_lock_held_(m_guestDeviceLock)
void AddPlan9Share(_In_ PCWSTR AccessName, _In_ PCWSTR Path, _In_ UINT32 Port, _In_ wsl::windows::common::hcs::Plan9ShareFlags Flags, _In_ HANDLE UserToken, _In_ PCWSTR VirtIoTag);
_Requires_lock_held_(m_guestDeviceLock)
GUID AddHdvShare(_In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken);
_Requires_lock_held_(m_guestDeviceLock)
GUID AddHdvShareWithOptions(
_In_ const GUID& DeviceId,
_In_ const GUID& ImplementationClsid,
_In_ std::wstring_view AccessName,
_In_ std::wstring_view Options,
_In_ std::wstring_view Path,
_In_ UINT32 Flags,
_In_ HANDLE UserToken);
_Requires_lock_held_(m_guestDeviceLock)
std::wstring AddVirtioFsShare(_In_ bool Admin, _In_ PCWSTR Path, _In_ PCWSTR Options, _In_opt_ HANDLE UserToken = nullptr);
@ -217,19 +195,6 @@ private:
void CollectCrashDumps(wil::unique_socket&& socket) const;
template <typename Interface>
wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ REFCLSID RefClsId, _In_ HANDLE UserToken)
{
auto revert = wil::impersonate_token(UserToken);
return wil::CoCreateInstance<Interface>(RefClsId, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
}
template <typename Class, typename Interface>
wil::com_ptr_t<Interface> CreateComServerAsUser(_In_ HANDLE UserToken)
{
return CreateComServerAsUser<Interface>(__uuidof(Class), UserToken);
}
std::shared_ptr<LxssRunningInstance> CreateInstanceInternal(
_In_ const GUID& InstanceId,
_In_ const LXSS_DISTRO_CONFIGURATION& Configuration,
@ -239,8 +204,6 @@ private:
_In_ bool LaunchSystemDistro = false,
_Out_opt_ ULONG* ConnectPort = nullptr);
DirectoryObjectLifetime CreateSectionObjectRoot(_In_ std::wstring_view RelativeRootPath, _In_ HANDLE UserToken) const;
_Requires_lock_held_(m_lock)
void EjectVhdLockHeld(_In_ PCWSTR VhdPath);
@ -269,9 +232,6 @@ private:
DiskMountResult MountDiskLockHeld(
_In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
_Requires_lock_held_(m_guestDeviceLock)
void MountSharedMemoryDeviceLockHeld(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb);
void WaitForPmemDeviceInVm(_In_ ULONG PmemId);
void OnCrash(_In_ LPCWSTR Details);
@ -302,12 +262,14 @@ private:
static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
wil::srwlock m_lock;
wil::srwlock m_guestDeviceLock;
std::shared_ptr<GuestDeviceManager> m_guestDeviceManager;
_Guarded_by_(m_guestDeviceLock) std::future<bool> m_drvfsInitialResult;
_Guarded_by_(m_guestDeviceLock) wil::unique_handle m_drvfsToken;
_Guarded_by_(m_guestDeviceLock) wil::unique_handle m_adminDrvfsToken;
_Guarded_by_(m_guestDeviceLock) std::map<VirtioFsShare, std::wstring> m_virtioFsShares;
_Guarded_by_(m_guestDeviceLock) std::map<UINT32, wil::com_ptr<IPlan9FileSystem>> m_plan9Servers;
wil::srwlock m_lock;
_Guarded_by_(m_lock) wil::unique_event m_terminatingEvent { wil::EventOptions::ManualReset };
_Guarded_by_(m_lock) wil::unique_event m_vmExitEvent { wil::EventOptions::ManualReset };
wil::unique_event m_vmCrashEvent{wil::EventOptions::ManualReset};
@ -339,12 +301,9 @@ private:
wsl::shared::SocketChannel m_miniInitChannel;
wil::unique_socket m_notifyChannel;
SE_SID m_userSid;
Microsoft::WRL::ComPtr<DeviceHostProxy> m_deviceHostSupport;
std::shared_ptr<LxssRunningInstance> m_systemDistro;
_Guarded_by_(m_lock) std::bitset<MAX_VHD_COUNT> m_lunBitmap;
_Guarded_by_(m_lock) std::map<AttachedDisk, DiskState> m_attachedDisks;
_Guarded_by_(m_guestDeviceLock) std::map<UINT32, wil::com_ptr<IPlan9FileSystem>> m_plan9Servers;
_Guarded_by_(m_guestDeviceLock) std::vector<DirectoryObjectLifetime> m_objectDirectories;
std::tuple<std::uint32_t, std::uint32_t, std::uint32_t> m_kernelVersion;
std::wstring m_kernelVersionString;
bool m_seccompAvailable;
@ -363,8 +322,6 @@ private:
_Guarded_by_(m_persistentMemoryLock) ULONG m_nextPersistentMemoryId = 0;
std::unique_ptr<wsl::core::INetworkingEngine> m_networkingEngine;
static const std::wstring c_defaultTag;
};
DEFINE_ENUM_FLAG_OPERATORS(WslCoreVm::DiskStateFlags);

View File

@ -327,7 +327,7 @@ class PolicyTest
const auto stop = std::chrono::steady_clock::now() + std::chrono::seconds{30};
for (;;)
{
Microsoft::WRL::ComPtr<ILxssUserSession> session;
wil::com_ptr<ILxssUserSession> session;
result = CoCreateInstance(CLSID_LxssUserSession, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&session));
if (result == expectedResult || std::chrono::steady_clock::now() > stop)
{

View File

@ -2448,8 +2448,7 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
// Validate that the shortcut is actually in the start menu
VERIFY_IS_TRUE(shortcutPath.find(startMenu) != std::string::npos);
Microsoft::WRL::ComPtr<IPersistFile> storage;
VERIFY_SUCCEEDED(shellLink->QueryInterface(IID_IPersistFile, &storage));
auto storage = shellLink.query<IPersistFile>();
VERIFY_SUCCEEDED(storage->Load(shortcutPath.c_str(), 0));