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");