From 8a9087d46793892937607066a1e9dbdc886f2da7 Mon Sep 17 00:00:00 2001 From: "Xin Wang (from Dev Box)" Date: Wed, 18 Mar 2026 19:34:19 +0800 Subject: [PATCH] Detect and fail with a clear error message when .wslconfig's swapFile setting points to a distribution's data VHD --- localization/strings/en-US/Resources.resw | 4 ++ src/windows/common/wslutil.cpp | 1 + src/windows/service/exe/LxssUserSession.cpp | 50 +++++++++++++++++++++ src/windows/service/inc/wslservice.idl | 1 + test/windows/UnitTests.cpp | 22 +++++++++ 5 files changed, 78 insertions(+) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 55a700b83..68c7e08b7 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -853,6 +853,10 @@ For information please visit https://aka.ms/wslinstall Failed to create the swap disk in '{}': {} {FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated + + The swap file path '{}' specified in .wslconfig conflicts with the data disk for distribution '{}'. Using a distribution's data disk as swap will destroy its contents. Please change the 'swapFile' setting in .wslconfig to a different path. + {FixedPlaceholder="{}"}{Locked=".wslconfig"}{Locked="swapFile"}Command line arguments, file names and string inserts should not be translated + Nested virtualization is not supported on this machine. diff --git a/src/windows/common/wslutil.cpp b/src/windows/common/wslutil.cpp index 421caf89e..c42079a87 100644 --- a/src/windows/common/wslutil.cpp +++ b/src/windows/common/wslutil.cpp @@ -85,6 +85,7 @@ static const std::map g_commonErrors{ X(WSL_E_DISTRIBUTION_NAME_NEEDED), X(WSL_E_INVALID_JSON), X(WSL_E_VM_CRASHED), + X(WSL_E_SWAP_FILE_CONFLICTS_WITH_DISTRO), X(WSL_E_NOT_A_LINUX_DISTRO), X(E_ACCESSDENIED), X_WIN32(ERROR_NOT_FOUND), diff --git a/src/windows/service/exe/LxssUserSession.cpp b/src/windows/service/exe/LxssUserSession.cpp index 2ad6469c9..5c0dab8e3 100644 --- a/src/windows/service/exe/LxssUserSession.cpp +++ b/src/windows/service/exe/LxssUserSession.cpp @@ -2829,6 +2829,56 @@ void LxssUserSessionImpl::_CreateVm() const auto userToken = wsl::windows::common::security::GetUserToken(TokenImpersonation); auto config = _GetResultantConfig(userToken.get()); + // Validate that the swap file path does not point to any distribution's data VHD. + // Using a distribution's VHD as swap would destroy its filesystem with mkswap. + if (!config.SwapFilePath.empty()) + { + auto swapFilePath = config.SwapFilePath; + if (!wsl::windows::common::string::IsPathComponentEqual(swapFilePath.extension().native(), wsl::windows::common::wslutil::c_vhdxFileExtension)) + { + swapFilePath += wsl::windows::common::wslutil::c_vhdxFileExtension; + } + + std::error_code error; + auto canonicalSwapPath = std::filesystem::weakly_canonical(swapFilePath, error); + if (error) + { + LOG_WIN32(error.value()); + canonicalSwapPath = std::move(swapFilePath); + } + + const wil::unique_hkey lxssKey = s_OpenLxssUserKey(); + for (const auto& distro : _EnumerateDistributions(lxssKey.get())) + { + std::filesystem::path distroVhdPath; + try + { + distroVhdPath = distro.ReadVhdFilePath(); + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + // skip distro whose registration is broken + continue; + } + + auto canonicalDistroPath = std::filesystem::weakly_canonical(distroVhdPath, error); + if (error) + { + LOG_WIN32(error.value()); + canonicalDistroPath = std::move(distroVhdPath); + } + + if (wsl::windows::common::string::IsPathComponentEqual(canonicalSwapPath.native(), canonicalDistroPath.native())) + { + auto distroName = distro.Read(Property::Name); + THROW_HR_WITH_USER_ERROR( + WSL_E_SWAP_FILE_CONFLICTS_WITH_DISTRO, + wsl::shared::Localization::MessageSwapFileConflictsWithDistroVhd(canonicalSwapPath.c_str(), distroName.c_str())); + } + } + } + // Initialize policies for the plugin interface. WSLVmCreationSettings userSettings{}; WI_SetFlagIf(userSettings.CustomConfigurationFlags, WSLUserConfigurationCustomKernel, !config.KernelPath.empty()); diff --git a/src/windows/service/inc/wslservice.idl b/src/windows/service/inc/wslservice.idl index c68ad7567..bc0613266 100644 --- a/src/windows/service/inc/wslservice.idl +++ b/src/windows/service/inc/wslservice.idl @@ -394,3 +394,4 @@ cpp_quote("#define WSL_E_DISK_CORRUPTED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_IT cpp_quote("#define WSL_E_DISTRIBUTION_NAME_NEEDED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + 0x30) /* 0x80040330 */") cpp_quote("#define WSL_E_INVALID_JSON MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + 0x31) /* 0x80040331 */") cpp_quote("#define WSL_E_VM_CRASHED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + 0x32) /* 0x80040332 */") +cpp_quote("#define WSL_E_SWAP_FILE_CONFLICTS_WITH_DISTRO MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + 0x33) /* 0x80040333 */") diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 8d5e6b39f..654850380 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -1798,6 +1798,28 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND validateSwapSize(L"200M"); } + TEST_METHOD(SwapFileConflictsWithDistroVhd) + { + WSL2_TEST_ONLY(); + + // Read the test distro's VHD path from the registry. + auto distroKey = OpenDistributionKey(LXSS_DISTRO_NAME_TEST_L); + auto basePath = wsl::windows::common::registry::ReadString(distroKey.get(), nullptr, L"BasePath", L""); + auto vhdFileName = wsl::windows::common::registry::ReadString(distroKey.get(), nullptr, L"VhdFileName", L"ext4.vhdx"); + auto vhdPath = std::filesystem::path(basePath) / vhdFileName; + + // Set swapFile to point to the distro's data VHD. + // Escape backslashes for .wslconfig ini parsing. + auto swapFileConfig = std::regex_replace(vhdPath.wstring(), std::wregex(L"\\\\"), L"\\\\"); + WslConfigChange configChange(LxssGenerateTestConfig() + L"\nswap=256MB\nswapFile=" + swapFileConfig); + + // Launching the distro should fail because swapFile conflicts with the distro's VHD. + auto [output, _] = LxsstuLaunchWslAndCaptureOutput(L"echo ok", -1); + + // Verify the error contains the expected error code. + VERIFY_IS_TRUE(output.find(L"WSL_E_SWAP_FILE_CONFLICTS_WITH_DISTRO") != std::wstring::npos); + } + TEST_METHOD(InitDoesntBlockSignals) { auto [output, _] = LxsstuLaunchWslAndCaptureOutput(L"grep -iF SigBlk < /proc/1/status");