Fix use-after-free in virtiofs request worker thread (#40792)
* Save state * Add test coverage * Format * Simplify socket creation * Apply PR feedback * Cleanup * Reduce to 15 iterations
Blue committed
Jun 16, 2026 at 11:03 UTC
509ce72fc4aab4bbb66dc2ce27f6f5a0730fca8e
13 files changed
+262
-150
src/windows/common/HandleIO.cpp
+56
-21
@@ -4,6 +4,7 @@
4
#include "HandleIO.h"
5
#pragma hdrstop
6
7
+using wsl::windows::common::io::AcceptHandle;
8
using wsl::windows::common::io::BufferWrapper;
9
using wsl::windows::common::io::DockerIORelayHandle;
10
using wsl::windows::common::io::EventHandle;
@@ -16,7 +17,6 @@ using wsl::windows::common::io::OverlappedIOHandle;
17
using wsl::windows::common::io::ReadHandle;
18
using wsl::windows::common::io::ReadNamedPipe;
19
using wsl::windows::common::io::ReadSocketMessageHandle;
19
-using wsl::windows::common::io::SingleAcceptHandle;
20
using wsl::windows::common::io::WriteHandle;
21
using wsl::windows::common::io::WriteNamedPipe;
22
@@ -360,41 +360,77 @@ void ReadNamedPipe::Collect()
360
ReadHandle::Collect();
361
}
362
363
-// SingleAcceptHandle
363
+// AcceptHandle
364
365
-SingleAcceptHandle::SingleAcceptHandle(HandleWrapper&& ListenSocket, HandleWrapper&& AcceptedSocket, std::function<void()>&& OnAccepted) :
366
- ListenSocket(std::move(ListenSocket)), AcceptedSocket(std::move(AcceptedSocket)), OnAccepted(std::move(OnAccepted))
365
+AcceptHandle::AcceptHandle(HandleWrapper&& ListenSocket, bool AcceptOnce, std::function<void(wil::unique_socket&&)>&& OnAccepted) :
366
+ ListenSocket(std::move(ListenSocket)), AcceptOnce(AcceptOnce), OnAccepted(std::move(OnAccepted))
367
{
368
Overlapped.hEvent = Event.get();
369
+
370
+ // Query the listen socket so accepted sockets can be created with a matching address family, type, and protocol.
371
+ WSAPROTOCOL_INFOW protocolInfo{};
372
+ int length = sizeof(protocolInfo);
373
+ THROW_LAST_ERROR_IF(
374
+ getsockopt(reinterpret_cast<SOCKET>(this->ListenSocket.Get()), SOL_SOCKET, SO_PROTOCOL_INFOW, reinterpret_cast<char*>(&protocolInfo), &length) ==
375
+ SOCKET_ERROR);
376
+
377
+ AddressFamily = protocolInfo.iAddressFamily;
378
+ SocketType = protocolInfo.iSocketType;
379
+ Protocol = protocolInfo.iProtocol;
380
}
381
371
-SingleAcceptHandle::~SingleAcceptHandle()
382
+AcceptHandle::~AcceptHandle()
383
{
384
if (State == IOHandleStatus::Pending)
385
{
375
- LOG_IF_WIN32_BOOL_FALSE(CancelIoEx(ListenSocket.Get(), &Overlapped));
386
+ CancelPendingIo(reinterpret_cast<SOCKET>(ListenSocket.Get()), Overlapped);
387
+ }
388
+}
389
377
- DWORD bytesProcessed{};
378
- DWORD flagsReturned{};
379
- if (!WSAGetOverlappedResult((SOCKET)ListenSocket.Get(), &Overlapped, &bytesProcessed, TRUE, &flagsReturned))
380
- {
381
- auto error = GetLastError();
382
- LOG_LAST_ERROR_IF(error != ERROR_CONNECTION_ABORTED && error != ERROR_OPERATION_ABORTED);
383
- }
390
+void AcceptHandle::CreateAcceptSocket()
391
+{
392
+ AcceptedSocket.reset(WSASocketW(AddressFamily, SocketType, Protocol, nullptr, 0, WSA_FLAG_OVERLAPPED));
393
+ THROW_LAST_ERROR_IF(!AcceptedSocket);
394
+
395
+ if (AddressFamily == AF_HYPERV)
396
+ {
397
+ ULONG enable = 1;
398
+ THROW_LAST_ERROR_IF(
399
+ setsockopt(AcceptedSocket.get(), HV_PROTOCOL_RAW, HVSOCKET_CONNECTED_SUSPEND, reinterpret_cast<char*>(&enable), sizeof(enable)) ==
400
+ SOCKET_ERROR);
401
+ }
402
+}
403
+
404
+void AcceptHandle::OnComplete()
405
+{
406
+ wsl::windows::common::socket::SetAcceptContext(AcceptedSocket.get(), reinterpret_cast<SOCKET>(ListenSocket.Get()));
407
+
408
+ OnAccepted(std::move(AcceptedSocket));
409
+
410
+ if (AcceptOnce)
411
+ {
412
+ State = IOHandleStatus::Completed;
413
+ }
414
+ else
415
+ {
416
+ State = IOHandleStatus::Standby;
417
}
418
}
419
387
-void SingleAcceptHandle::Schedule()
420
+void AcceptHandle::Schedule()
421
{
422
WI_ASSERT(State == IOHandleStatus::Standby);
423
424
+ CreateAcceptSocket();
425
+
426
+ Event.ResetEvent();
427
+
428
// Schedule the accept.
429
DWORD bytesReturned{};
393
- if (AcceptEx((SOCKET)ListenSocket.Get(), (SOCKET)AcceptedSocket.Get(), &AcceptBuffer, 0, sizeof(SOCKADDR_STORAGE), sizeof(SOCKADDR_STORAGE), &bytesReturned, &Overlapped))
430
+ if (AcceptEx((SOCKET)ListenSocket.Get(), AcceptedSocket.get(), &AcceptBuffer, 0, sizeof(SOCKADDR_STORAGE), sizeof(SOCKADDR_STORAGE), &bytesReturned, &Overlapped))
431
{
432
// Accept completed immediately.
396
- State = IOHandleStatus::Completed;
397
- OnAccepted();
433
+ OnComplete();
434
}
435
else
436
{
@@ -405,7 +441,7 @@ void SingleAcceptHandle::Schedule()
441
}
442
}
443
408
-void SingleAcceptHandle::Collect()
444
+void AcceptHandle::Collect()
445
{
446
WI_ASSERT(State == IOHandleStatus::Pending);
447
@@ -414,11 +450,10 @@ void SingleAcceptHandle::Collect()
450
451
THROW_IF_WIN32_BOOL_FALSE(WSAGetOverlappedResult((SOCKET)ListenSocket.Get(), &Overlapped, &bytesReceived, false, &flagsReturned));
452
417
- State = IOHandleStatus::Completed;
418
- OnAccepted();
453
+ OnComplete();
454
}
455
421
-HANDLE SingleAcceptHandle::GetHandle() const
456
+HANDLE AcceptHandle::GetHandle() const
457
{
458
return Event.get();
459
}
src/windows/common/HandleIO.h
+14
-7
@@ -139,25 +139,32 @@ private:
139
bool m_connected = false;
140
};
141
142
-class SingleAcceptHandle : public OverlappedIOHandle
142
+class AcceptHandle : public OverlappedIOHandle
143
{
144
public:
145
- NON_COPYABLE(SingleAcceptHandle)
146
- NON_MOVABLE(SingleAcceptHandle)
145
+ NON_COPYABLE(AcceptHandle)
146
+ NON_MOVABLE(AcceptHandle)
147
148
- SingleAcceptHandle(HandleWrapper&& ListenSocket, HandleWrapper&& AcceptedSocket, std::function<void()>&& OnAccepted);
149
- ~SingleAcceptHandle();
148
+ AcceptHandle(HandleWrapper&& ListenSocket, bool AcceptOnce, std::function<void(wil::unique_socket&&)>&& OnAccepted);
149
+ ~AcceptHandle();
150
151
void Schedule() override;
152
void Collect() override;
153
HANDLE GetHandle() const override;
154
155
private:
156
+ void CreateAcceptSocket();
157
+ void OnComplete();
158
+
159
HandleWrapper ListenSocket;
157
- HandleWrapper AcceptedSocket;
160
+ wil::unique_socket AcceptedSocket;
161
+ int AddressFamily{};
162
+ int SocketType{};
163
+ int Protocol{};
164
+ bool AcceptOnce{};
165
wil::unique_event Event{wil::EventOptions::ManualReset};
166
OVERLAPPED Overlapped{};
160
- std::function<void()> OnAccepted;
167
+ std::function<void(wil::unique_socket&&)> OnAccepted;
168
char AcceptBuffer[2 * sizeof(SOCKADDR_STORAGE)];
169
};
170
src/windows/common/hvsocket.cpp
-12
@@ -37,18 +37,6 @@ void InitializeWildcardSocketAddress(_Out_ PSOCKADDR_HV Address)
37
}
38
} // namespace
39
40
-std::optional<wil::unique_socket> wsl::windows::common::hvsocket::CancellableAccept(
41
- _In_ SOCKET ListenSocket, _In_ DWORD Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
42
-{
43
- wil::unique_socket Socket = Create();
44
- if (!socket::CancellableAccept(ListenSocket, Socket.get(), Timeout, ExitHandle, Location))
45
- {
46
- return {};
47
- }
48
-
49
- return Socket;
50
-}
51
-
40
wil::unique_socket wsl::windows::common::hvsocket::Connect(
41
_In_ const GUID& VmId, _In_ unsigned long Port, _In_opt_ HANDLE ExitHandle, _In_opt_ ULONG Timeout, _In_ const std::source_location& Location)
42
{
src/windows/common/hvsocket.hpp
-6
@@ -19,12 +19,6 @@ Abstract:
19
20
namespace wsl::windows::common::hvsocket {
21
22
-std::optional<wil::unique_socket> CancellableAccept(
23
- _In_ SOCKET ListenSocket,
24
- _In_ DWORD Timeout,
25
- _In_opt_ HANDLE ExitHandle = nullptr,
26
- const std::source_location& Location = std::source_location::current());
27
-
22
wil::unique_socket Connect(
23
_In_ const GUID& VmId,
24
_In_ unsigned long Port,
src/windows/common/socket.cpp
+21
-10
@@ -26,30 +26,41 @@ void wsl::windows::common::socket::SetAcceptContext(_In_ SOCKET AcceptedSocket,
26
std::format("{}", Location).c_str());
27
}
28
29
-bool wsl::windows::common::socket::CancellableAccept(
30
- _In_ SOCKET ListenSocket, _In_ SOCKET Socket, _In_ DWORD Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
29
+std::optional<wil::unique_socket> wsl::windows::common::socket::CancellableAccept(
30
+ _In_ SOCKET ListenSocket, _In_ DWORD Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
31
{
32
io::MultiHandleWait io;
33
34
- bool accepted = false;
34
+ std::optional<wil::unique_socket> accepted;
35
36
- io.AddHandle(std::make_unique<io::SingleAcceptHandle>(ListenSocket, Socket, [&]() { accepted = true; }), io::MultiHandleWait::CancelOnCompleted);
36
+ io.AddHandle(
37
+ std::make_unique<io::AcceptHandle>(
38
+ ListenSocket, true, [&accepted](wil::unique_socket&& socket) { accepted = std::move(socket); }),
39
+ io::MultiHandleWait::CancelOnCompleted);
40
41
if (ExitHandle != nullptr)
42
{
43
io.AddHandle(std::make_unique<io::EventHandle>(ExitHandle), io::MultiHandleWait::CancelOnCompleted);
44
}
45
43
- io.Run(std::chrono::milliseconds(Timeout));
44
-
45
- if (!accepted)
46
+ std::optional<std::chrono::milliseconds> timeout;
47
+ if (Timeout != INFINITE)
48
{
47
- return false; // Accept was cancelled by the exit event.
49
+ timeout = std::chrono::milliseconds(Timeout);
50
}
51
50
- SetAcceptContext(Socket, ListenSocket, Location);
52
+ try
53
+ {
54
+
55
+ io.Run(timeout);
56
+ }
57
+ catch (...)
58
+ {
59
+ auto hr = wil::ResultFromCaughtException();
60
+ THROW_HR_MSG(hr, "Failed to accept socket. From: %hs", std::format("{}", Location).c_str());
61
+ }
62
52
- return true;
63
+ return accepted;
64
}
65
66
std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(
src/windows/common/socket.hpp
+1
-2
@@ -21,9 +21,8 @@ namespace wsl::windows::common::socket {
21
// Sets SO_UPDATE_ACCEPT_CONTEXT on a socket accepted via AcceptEx to mark it as connected.
22
void SetAcceptContext(_In_ SOCKET AcceptedSocket, _In_ SOCKET ListenSocket, _In_ const std::source_location& Location = std::source_location::current());
23
24
-bool CancellableAccept(
24
+std::optional<wil::unique_socket> CancellableAccept(
25
_In_ SOCKET ListenSocket,
26
- _In_ SOCKET Socket,
26
_In_ DWORD Timeout,
27
_In_opt_ HANDLE ExitHandle,
28
_In_ const std::source_location& Location = std::source_location::current());
src/windows/service/exe/HcsVirtualMachine.cpp
+2
-2
@@ -381,7 +381,7 @@ try
381
{
382
RETURN_HR_IF_NULL(E_POINTER, Socket);
383
384
- auto socket = wsl::windows::common::hvsocket::CancellableAccept(m_listenSocket.get(), m_bootTimeoutMs, m_vmExitEvent.get());
384
+ auto socket = socket::CancellableAccept(m_listenSocket.get(), m_bootTimeoutMs, m_vmExitEvent.get());
385
THROW_HR_IF(E_ABORT, !socket.has_value());
386
387
*Socket = reinterpret_cast<HANDLE>(socket->release());
@@ -924,4 +924,4 @@ try
924
}
925
CATCH_RETURN()
926
927
-} // namespace wsl::windows::service::wslc
\ No newline at end of file
927
+} // namespace wsl::windows::service::wslc
src/windows/service/exe/WslCoreVm.cpp
+99
-75
@@ -856,7 +856,7 @@ WslCoreVm::~WslCoreVm() noexcept
856
857
wil::unique_socket WslCoreVm::AcceptConnection(_In_ DWORD ReceiveTimeout, _In_ const std::source_location& Location) const
858
{
859
- auto socket = hvsocket::CancellableAccept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get(), Location);
859
+ auto socket = socket::CancellableAccept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get(), Location);
860
THROW_HR_IF(E_ABORT, !socket.has_value());
861
862
if (ReceiveTimeout != 0)
@@ -1087,7 +1087,7 @@ void WslCoreVm::CollectCrashDumps(wil::unique_socket&& listenSocket) const
1087
{
1088
try
1089
{
1090
- auto socket = hvsocket::CancellableAccept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
1090
+ auto socket = socket::CancellableAccept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
1091
if (!socket.has_value())
1092
{
1093
break; // VM is exiting.
@@ -2617,92 +2617,116 @@ try
2617
{
2618
wsl::windows::common::wslutil::SetThreadDescription(L"VirtioFs - Worker");
2619
2620
- for (;;)
2621
- {
2622
- // Create a worker thread to handle each request.
2620
+ io::MultiHandleWait io;
2621
2624
- auto socket = hvsocket::CancellableAccept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
2625
- if (!socket.has_value())
2626
- {
2627
- break;
2628
- }
2622
+ io.AddHandle(std::make_unique<io::AcceptHandle>(listenSocket.get(), false, [this, &io](wil::unique_socket&& socket) {
2623
+ auto channel = std::make_shared<wsl::shared::SocketChannel>(std::move(socket), "VirtioFs");
2624
+ auto buffer = std::make_shared<std::vector<gsl::byte>>();
2625
+ auto pendingBytes = std::make_shared<std::vector<gsl::byte>>();
2626
2630
- wsl::shared::SocketChannel channel{std::move(socket.value()), "VirtioFs", {m_terminatingEvent.get()}};
2631
- std::thread([this, channel = std::move(channel)]() mutable {
2632
- try
2633
- {
2634
- wsl::windows::common::wslutil::SetThreadDescription(L"VirtioFs - Request");
2627
+ io.AddHandle(
2628
+ std::make_unique<io::ReadSocketMessageHandle>(
2629
+ io::HandleWrapper(channel->Socket()),
2630
+ *buffer,
2631
+ *pendingBytes,
2632
+ [this, &io, channel, buffer, pendingBytes](const gsl::span<gsl::byte>& message) {
2633
+ if (message.empty())
2634
+ {
2635
+ return; // Channel closed, exit.
2636
+ }
2637
2636
- auto transaction = channel.ReceiveTransaction();
2637
- auto [message, span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
2638
- if (message == nullptr)
2639
- {
2640
- return;
2641
- }
2638
+ THROW_HR_IF_MSG(
2639
+ E_UNEXPECTED, !pendingBytes->empty(), "Received message with additional bytes: %zu", pendingBytes->size());
2640
2643
- auto respondWithTag = [&](const std::wstring& tag, const std::wstring& source, HRESULT result) {
2644
- // Respond to the guest with the tag that should be used to mount the device.
2641
+ try
2642
+ {
2643
+ auto response = ProcessVirtioFsRequest(message);
2644
2646
- wsl::shared::MessageWriter<LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE> response(LxInitMessageAddVirtioFsDeviceResponse);
2647
- response->Result = SUCCEEDED(result) ? 0 : EINVAL; // TODO: Improved HRESULT -> errno mapping.
2648
- response.WriteString(response->TagOffset, tag);
2649
- response.WriteString(response->SourceOffset, source);
2645
+ // Move the socket out of the channel into the WriteHandle so it is closed once the reply is sent.
2646
+ io.AddHandle(std::make_unique<io::WriteHandle>(channel->Release(), response), io::MultiHandleWait::IgnoreErrors);
2647
+ }
2648
+ CATCH_LOG();
2649
+ }),
2650
+ io::MultiHandleWait::IgnoreErrors);
2651
+ }));
2652
2651
- transaction.Send<LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE>(response.Span());
2652
- };
2653
+ io.AddHandle(std::make_unique<io::EventHandle>(m_terminatingEvent.get()), io::MultiHandleWait::CancelOnCompleted);
2654
2654
- if (message->MessageType == LxInitMessageAddVirtioFsDevice)
2655
- {
2656
- std::wstring tag;
2657
- std::wstring source;
2658
- const auto result = wil::ResultFromException([this, span, &tag, &source]() {
2659
- const auto* addShare = gslhelpers::try_get_struct<LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE>(span);
2660
- THROW_HR_IF(E_UNEXPECTED, !addShare);
2661
-
2662
- const auto path = wsl::shared::string::FromSpan(span, addShare->PathOffset);
2663
- const auto pathWide = wsl::shared::string::MultiByteToWide(path);
2664
- const auto options = wsl::shared::string::FromSpan(span, addShare->OptionsOffset);
2665
- const auto optionsWide = wsl::shared::string::MultiByteToWide(options);
2666
-
2667
- // Acquire the lock and attempt to add the device.
2668
- auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2669
- std::tie(tag, source) = AddVirtioFsShare(addShare->Admin, pathWide.c_str(), optionsWide.c_str());
2670
- });
2671
-
2672
- respondWithTag(tag, source, result);
2673
- }
2674
- else if (message->MessageType == LxInitMessageRemountVirtioFsDevice)
2675
- {
2676
- std::wstring newTag;
2677
- std::wstring source;
2678
- const auto result = wil::ResultFromException([this, span, &newTag, &source]() {
2679
- const auto* remountShare = gslhelpers::try_get_struct<LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE>(span);
2680
- THROW_HR_IF(E_UNEXPECTED, !remountShare);
2655
+ io.Run({});
2656
+}
2657
+CATCH_LOG()
2658
2682
- const std::string tag = wsl::shared::string::FromSpan(span, remountShare->TagOffset);
2683
- const auto tagWide = wsl::shared::string::MultiByteToWide(tag);
2684
- auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2685
- const auto foundShare = FindVirtioFsShare(tagWide.c_str(), !remountShare->Admin);
2686
- THROW_HR_IF_MSG(E_UNEXPECTED, !foundShare.has_value(), "Unknown tag %ls", tagWide.c_str());
2659
+std::vector<char> WslCoreVm::ProcessVirtioFsRequest(_In_ gsl::span<gsl::byte> Request)
2660
+{
2661
+ const auto* header = gslhelpers::try_get_struct<MESSAGE_HEADER>(Request);
2662
+ THROW_HR_IF(E_UNEXPECTED, !header);
2663
2688
- std::tie(newTag, source) =
2689
- AddVirtioFsShare(remountShare->Admin, foundShare->Path.c_str(), foundShare->OptionsString().c_str());
2664
+ WSL_LOG("VirtiofsMessageRequest", TraceLoggingValue(header->PrettyPrint().c_str(), "Content"));
2665
2691
- WI_ASSERT(source == foundShare->Path);
2692
- });
2666
+ auto buildResponse = [header](const std::wstring& tag, const std::wstring& source, HRESULT result) {
2667
+ // Respond to the guest with the tag that should be used to mount the device.
2668
+ wsl::shared::MessageWriter<LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE> response(LxInitMessageAddVirtioFsDeviceResponse);
2669
+ response->Result = SUCCEEDED(result) ? 0 : EINVAL; // TODO: Improved HRESULT -> errno mapping.
2670
+ response.WriteString(response->TagOffset, tag);
2671
+ response.WriteString(response->SourceOffset, source);
2672
2694
- respondWithTag(newTag, source, result);
2695
- }
2696
- else
2697
- {
2698
- THROW_HR_MSG(E_UNEXPECTED, "Unexpected MessageType %d", message->MessageType);
2699
- }
2700
- }
2701
- CATCH_LOG()
2702
- }).detach();
2673
+ // Echo the request's transaction id and mark the message as the first (and only) reply.
2674
+ response->Header.TransactionId = header->TransactionId;
2675
+ response->Header.TransactionStep = static_cast<unsigned int>(TRANSACTION_STEP::FIRST_REPLY);
2676
+
2677
+ WSL_LOG("VirtiofsMessageResponse", TraceLoggingValue(response->PrettyPrint().c_str(), "Content"));
2678
+
2679
+ const auto span = response.Span();
2680
+ return std::vector<char>(reinterpret_cast<const char*>(span.data()), reinterpret_cast<const char*>(span.data()) + span.size());
2681
+ };
2682
+
2683
+ if (header->MessageType == LxInitMessageAddVirtioFsDevice)
2684
+ {
2685
+ std::wstring tag;
2686
+ std::wstring source;
2687
+ const auto result = wil::ResultFromException([&]() {
2688
+ const auto* addShare = gslhelpers::try_get_struct<LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE>(Request);
2689
+ THROW_HR_IF(E_UNEXPECTED, !addShare);
2690
+
2691
+ const auto path = wsl::shared::string::FromSpan(Request, addShare->PathOffset);
2692
+ const auto pathWide = wsl::shared::string::MultiByteToWide(path);
2693
+ const auto options = wsl::shared::string::FromSpan(Request, addShare->OptionsOffset);
2694
+ const auto optionsWide = wsl::shared::string::MultiByteToWide(options);
2695
+
2696
+ // Acquire the lock and attempt to add the device.
2697
+ auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2698
+ std::tie(tag, source) = AddVirtioFsShare(addShare->Admin, pathWide.c_str(), optionsWide.c_str());
2699
+ });
2700
+
2701
+ return buildResponse(tag, source, result);
2702
+ }
2703
+ else if (header->MessageType == LxInitMessageRemountVirtioFsDevice)
2704
+ {
2705
+ std::wstring newTag;
2706
+ std::wstring source;
2707
+ const auto result = wil::ResultFromException([&]() {
2708
+ const auto* remountShare = gslhelpers::try_get_struct<LX_INIT_REMOUNT_VIRTIOFS_SHARE_MESSAGE>(Request);
2709
+ THROW_HR_IF(E_UNEXPECTED, !remountShare);
2710
+
2711
+ const std::string tag = wsl::shared::string::FromSpan(Request, remountShare->TagOffset);
2712
+ const auto tagWide = wsl::shared::string::MultiByteToWide(tag);
2713
+ auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2714
+ const auto foundShare = FindVirtioFsShare(tagWide.c_str(), !remountShare->Admin);
2715
+ THROW_HR_IF_MSG(E_UNEXPECTED, !foundShare.has_value(), "Unknown tag %ls", tagWide.c_str());
2716
+
2717
+ std::tie(newTag, source) =
2718
+ AddVirtioFsShare(remountShare->Admin, foundShare->Path.c_str(), foundShare->OptionsString().c_str());
2719
+
2720
+ WI_ASSERT(source == foundShare->Path);
2721
+ });
2722
+
2723
+ return buildResponse(newTag, source, result);
2724
+ }
2725
+ else
2726
+ {
2727
+ THROW_HR_MSG(E_UNEXPECTED, "Unexpected MessageType %d", header->MessageType);
2728
}
2729
}
2705
-CATCH_LOG()
2730
2731
std::string WslCoreVm::s_GetMountTargetName(_In_ PCWSTR Disk, _In_opt_ PCWSTR Name, _In_ int PartitionIndex)
2732
{
src/windows/service/exe/WslCoreVm.h
+2
@@ -251,6 +251,8 @@ private:
251
252
void VirtioFsWorker(_In_ const wil::unique_socket& socket);
253
254
+ std::vector<char> ProcessVirtioFsRequest(_In_ gsl::span<gsl::byte> Request);
255
+
256
static std::string s_GetMountTargetName(_In_ PCWSTR Disk, _In_opt_ PCWSTR Name, _In_ int PartitionIndex);
257
258
static LX_INIT_DRVFS_MOUNT s_InitializeDrvFs(_Inout_ WslCoreVm* VmContext, _In_ HANDLE UserToken);
src/windows/wslcsession/WSLCVirtualMachine.cpp
+1
-1
@@ -1259,7 +1259,7 @@ void WSLCVirtualMachine::CollectCrashDumps(wil::unique_socket&& listenSocket)
1259
{
1260
try
1261
{
1262
- auto socket = hvsocket::CancellableAccept(listenSocket.get(), INFINITE, m_vmTerminatingEvent.get());
1262
+ auto socket = socket::CancellableAccept(listenSocket.get(), INFINITE, m_vmTerminatingEvent.get());
1263
if (!socket)
1264
{
1265
// VM is exiting.
src/windows/wslrelay/localhost.cpp
+4
-8
@@ -291,15 +291,11 @@ try
291
{
292
// Begin accepting connections until the relay is stopped.
293
294
- const int AddressFamily = WindowsAddressFamily(Arguments->Family);
295
-
294
for (;;)
295
{
298
- wil::unique_socket InetSocket(WSASocket(AddressFamily, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
299
- THROW_LAST_ERROR_IF(!InetSocket);
300
-
301
- if (!wsl::windows::common::socket::CancellableAccept(
302
- Arguments->ListenSocket.get(), InetSocket.get(), INFINITE, Arguments->ExitEvent.get()))
296
+ auto InetSocket =
297
+ wsl::windows::common::socket::CancellableAccept(Arguments->ListenSocket.get(), INFINITE, Arguments->ExitEvent.get());
298
+ if (!InetSocket)
299
{
300
break; // Exit event was signaled, exit.
301
}
@@ -308,7 +304,7 @@ try
304
305
WSL_LOG("PortRelayUsage", TraceLoggingValue(Arguments->Family, "family"), TraceLoggingValue(Arguments->Port, "port"), TraceLoggingLevel(WINEVENT_LEVEL_INFO));
306
311
- auto RelayThread = std::thread([Arguments, InetSocket = std::move(InetSocket)]() {
307
+ auto RelayThread = std::thread([Arguments, InetSocket = std::move(*InetSocket)]() {
308
try
309
{
310
wsl::windows::common::wslutil::SetThreadDescription(L"Port relay");
src/windows/wslrelay/main.cpp
+3
-5
@@ -123,17 +123,15 @@ try
123
124
THROW_LAST_ERROR_IF(listen(listenSocket.get(), 1) == SOCKET_ERROR);
125
126
- const wil::unique_socket socket(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
127
- THROW_LAST_ERROR_IF(!socket);
128
-
129
- if (!wsl::windows::common::socket::CancellableAccept(listenSocket.get(), socket.get(), INFINITE, exitEvent.get()))
126
+ auto socket = wsl::windows::common::socket::CancellableAccept(listenSocket.get(), INFINITE, exitEvent.get());
127
+ if (!socket)
128
{
129
return 1;
130
}
131
132
// Begin the relay.
133
wsl::windows::common::relay::BidirectionalRelay(
136
- reinterpret_cast<HANDLE>(socket.get()), pipe.get(), 0x1000, wsl::windows::common::relay::RelayFlags::LeftIsSocket);
134
+ reinterpret_cast<HANDLE>(socket->get()), pipe.get(), 0x1000, wsl::windows::common::relay::RelayFlags::LeftIsSocket);
135
136
break;
137
}
test/windows/DrvFsTests.cpp
+59
-1
@@ -409,6 +409,59 @@ public:
409
VERIFY_IS_TRUE(out.find(L"test-file.txt") != std::wstring::npos);
410
}
411
412
+ void DrvfsMountManyVirtioFsShares(DrvFsMode Mode)
413
+ {
414
+ if (Mode != DrvFsMode::VirtioFs)
415
+ {
416
+ LogSkipped("This test is only applicable to VirtioFs");
417
+ return;
418
+ }
419
+
420
+ WINDOWS_11_TEST_ONLY();
421
+ SKIP_TEST_ARM64();
422
+
423
+ constexpr auto c_iterations = 15;
424
+ auto testDir = std::filesystem::current_path() / "virtiofs-loop-test";
425
+
426
+ auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
427
+ LxsstuLaunchWsl(L"umount /tmp/virtiofs-loop-test-*");
428
+
429
+ std::error_code ec;
430
+ std::filesystem::remove_all(testDir, ec);
431
+ });
432
+
433
+ for (int i = 0; i < c_iterations; ++i)
434
+ {
435
+ const auto sourceDir = testDir / std::to_string(i);
436
+ std::filesystem::create_directories(sourceDir);
437
+
438
+ const auto expected = std::format("virtiofs share {}", i);
439
+ {
440
+ std::ofstream markerFile(std::filesystem::path(sourceDir) / L"marker");
441
+ markerFile << expected;
442
+ }
443
+
444
+ const auto mountPoint = std::format(L"/tmp/virtiofs-loop-test-{}", i);
445
+
446
+ // Mount the share.
447
+ VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"mkdir -p '{}'", mountPoint)), 0);
448
+ VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"mount -t drvfs '{}' '{}'", sourceDir.string(), mountPoint)), 0);
449
+
450
+ // Validate that it can be accessed.
451
+ {
452
+ auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"cat '{}/marker'", mountPoint));
453
+ VERIFY_ARE_EQUAL(out, wsl::shared::string::MultiByteToWide(expected));
454
+ }
455
+
456
+ // Validate the mount options.
457
+ {
458
+ auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"findmnt -ln '{}'", mountPoint));
459
+
460
+ VerifyPatternMatch(wsl::shared::string::WideToMultiByte(out.c_str()), std::format("{} * virtiofs rw,relatime\n", mountPoint));
461
+ }
462
+ }
463
+ }
464
+
465
// DrvFsTests Private Methods
466
private:
467
static VOID CreateDrvFsTestFiles(bool Metadata)
@@ -1303,6 +1356,11 @@ class WSL1 : public DrvFsTests
1356
{ \
1357
DrvFsTests::DrvFsMountUnicodePath(DrvFsMode::##_mode##); \
1358
} \
1359
+\
1360
+ WSL2_TEST_METHOD(DrvfsMountManyVirtioFsShares) \
1361
+ { \
1362
+ DrvFsTests::DrvfsMountManyVirtioFsShares(DrvFsMode::##_mode##); \
1363
+ } \
1364
}
1365
1366
WSL2_DRVFS_TEST_CLASS(Plan9);
@@ -1313,4 +1371,4 @@ WSL2_DRVFS_TEST_CLASS(VirtioFs);
1371
// TODO: Enable again once the issue is resolved
1372
// WSL2_DRVFS_TEST_CLASS(Virtio9p);
1373
1316
-} // namespace DrvFsTests
\ No newline at end of file
1374
+} // namespace DrvFsTests