WSL2 shutdown can deadlock while process creation waits for OOBE
Summary
WslCoreInstance::CreateLxProcess() waits for an in-progress OOBE while holding WslCoreInstance::m_lock. The shutdown path needs the same lock to stop the instance and signal its destruction event.
If another process launch arrives while OOBE is waiting for user input, distribution termination or shutdown can remain blocked until OOBE completes.
Code analysis
CreateLxProcess() acquires m_lock before checking m_oobeCompleteEvent:
std::lock_guard lock(m_lock);
if (m_oobeCompleteEvent && !m_oobeCompleteEvent.is_signaled())
{
m_oobeCompleteEvent.wait();
}
RequestStop() and Stop() also acquire m_lock. Stop() signals m_destroyingEvent, but it cannot do so while the process-creation thread owns the lock.
The resulting dependency is:
- A process-creation thread owns
m_lock and waits for OOBE completion.
- Shutdown waits for
m_lock before it can stop the instance.
- The process-creation wait does not observe
m_destroyingEvent.
OOBE is intentionally allowed to wait indefinitely for user interaction. That wait should not retain the instance lock or prevent shutdown.
Expected behavior
An OOBE flow may remain active for an arbitrary duration, but distribution termination and shutdown must still be able to stop the instance.
Proposed change
Capture stable handles for the OOBE-complete and instance-destroying events while holding m_lock, release the lock, and wait for either event. After reacquiring the lock, revalidate that the instance is still running before continuing process creation.
Proposed validation
Add a WSL2 regression test that:
- starts an OOBE command that remains active;
- starts a second process creation that waits for OOBE;
- terminates the distribution concurrently;
- verifies that termination completes before OOBE's natural completion;
- verifies that the waiting client processes exit.
This report is based on static source analysis and a deterministic regression scenario. No machine logs are attached.
WSL2 shutdown can deadlock while process creation waits for OOBE
Summary
WslCoreInstance::CreateLxProcess()waits for an in-progress OOBE while holdingWslCoreInstance::m_lock. The shutdown path needs the same lock to stop the instance and signal its destruction event.If another process launch arrives while OOBE is waiting for user input, distribution termination or shutdown can remain blocked until OOBE completes.
Code analysis
CreateLxProcess()acquiresm_lockbefore checkingm_oobeCompleteEvent:RequestStop()andStop()also acquirem_lock.Stop()signalsm_destroyingEvent, but it cannot do so while the process-creation thread owns the lock.The resulting dependency is:
m_lockand waits for OOBE completion.m_lockbefore it can stop the instance.m_destroyingEvent.OOBE is intentionally allowed to wait indefinitely for user interaction. That wait should not retain the instance lock or prevent shutdown.
Expected behavior
An OOBE flow may remain active for an arbitrary duration, but distribution termination and shutdown must still be able to stop the instance.
Proposed change
Capture stable handles for the OOBE-complete and instance-destroying events while holding
m_lock, release the lock, and wait for either event. After reacquiring the lock, revalidate that the instance is still running before continuing process creation.Proposed validation
Add a WSL2 regression test that:
This report is based on static source analysis and a deterministic regression scenario. No machine logs are attached.