Fix incorrect timeout causing WSL1 OOBE to fail if the OOBE process takes longer than 30 seconds (#13517)

* Fix incorrect timeout causing WSL1 OOBE to fail if the OOBE process takes longer than 30 seconds * Pass the timeout to WaitForMessage

Blue committed Sep 25, 2025 at 02:58 UTC 332efe1a8dfdcb3d18a2d37e195cdec014f7d43f
3 files changed +10 -7
src/windows/common/LxssMessagePort.cpp
+4 -5
@@ -19,7 +19,6 @@ Abstract:
19 // Defines.
20
21 #define LAUNCH_PROCESS_DEFAULT_BUFFER_SIZE 1024
22 -#define LAUNCH_PROCESS_DEFAULT_TIMEOUT_MS 30000
22
23 LxssMessagePort::LxssMessagePort(_In_ HANDLE MessagePort) : m_messagePort(MessagePort), m_messageEvent(wil::EventOptions::None)
24 {
@@ -52,7 +51,7 @@ std::shared_ptr<LxssPort> LxssMessagePort::CreateSessionLeader(_In_ HANDLE Clien
51 LX_INIT_CREATE_SESSION Message{{LxInitMessageCreateSession, sizeof(Message)}, MarshalId};
52
53 Send(&Message, sizeof(Message));
55 - auto LocalMessagePort = m_serverPort->WaitForConnection(LAUNCH_PROCESS_DEFAULT_TIMEOUT_MS);
54 + auto LocalMessagePort = m_serverPort->WaitForConnection(c_defaultMessageTimeout);
55 ReleaseConsole.release();
56 return LocalMessagePort;
57 }
@@ -156,7 +155,7 @@ void LxssMessagePort::Receive(_Out_writes_bytes_(Length) PVOID Buffer, _In_ ULON
155 return;
156 }
157
159 -std::vector<gsl::byte> LxssMessagePort::Receive()
158 +std::vector<gsl::byte> LxssMessagePort::Receive(DWORD Timeout)
159 {
160 IO_STATUS_BLOCK IoStatus;
161 std::vector<gsl::byte> Message;
@@ -170,7 +169,7 @@ std::vector<gsl::byte> LxssMessagePort::Receive()
169
170 if (Status == STATUS_PENDING)
171 {
173 - WaitForMessage(&IoStatus);
172 + WaitForMessage(&IoStatus, Timeout);
173 Status = IoStatus.Status;
174 SizeReceived = static_cast<ULONG>(IoStatus.Information);
175 }
@@ -274,7 +273,7 @@ wil::unique_handle LxssMessagePort::UnmarshalVfsFile(_In_ LXBUS_IPC_HANDLE_ID Vf
273
274 void LxssMessagePort::WaitForMessage(_In_ PIO_STATUS_BLOCK IoStatus, _In_ DWORD Timeout) const
275 {
277 - const DWORD WaitStatus = WaitForSingleObject(m_messageEvent.get(), LAUNCH_PROCESS_DEFAULT_TIMEOUT_MS);
276 + const DWORD WaitStatus = WaitForSingleObject(m_messageEvent.get(), Timeout);
277 if (WaitStatus == WAIT_TIMEOUT)
278 {
279 IO_STATUS_BLOCK IoStatusCancel;
src/windows/common/LxssMessagePort.h
+3 -1
@@ -21,6 +21,8 @@ class LxssServerPort;
21 class LxssMessagePort : public LxssPort
22 {
23 public:
24 + static inline DWORD c_defaultMessageTimeout = 30000;
25 +
26 LxssMessagePort(_In_ HANDLE MessagePort);
27 LxssMessagePort(_In_ LxssMessagePort&& Source);
28 LxssMessagePort(_In_ std::unique_ptr<LxssMessagePort>&& SourcePointer);
@@ -46,7 +48,7 @@ public:
48 LXBUS_IPC_PROCESS_ID
49 MarshalProcess(_In_ HANDLE ProcessHandle, _In_ bool TerminateOnClose) const;
50
49 - std::vector<gsl::byte> Receive();
51 + std::vector<gsl::byte> Receive(DWORD Timeout = c_defaultMessageTimeout);
52
53 void ReleaseConsole(_In_ LXBUS_IPC_CONSOLE_ID ConsoleId) const;
54
src/windows/service/exe/LxssInstance.cpp
+3 -1
@@ -551,7 +551,9 @@ wil::unique_handle LxssInstance::_CreateLxProcess(
551 m_oobeThread = std::thread([this, OobeMessagePort = std::move(OobeMessagePort), registration = std::move(registration)]() mutable {
552 try
553 {
554 - auto Message = OobeMessagePort->Receive();
554 + // N.B. The LX_INIT_OOBE_RESULT message is only sent once the OOBE process completes, which might be waiting on user input.
555 + // Do no set a timeout here otherwise the OOBE flow will fail if the OOBE process takes longer than expected.
556 + auto Message = OobeMessagePort->Receive(INFINITE);
557 auto* OobeResult = gslhelpers::try_get_struct<LX_INIT_OOBE_RESULT>(gsl::make_span(Message));
558 THROW_HR_IF(E_INVALIDARG, !OobeResult || (OobeResult->Header.MessageType != LxInitOobeResult));
559