Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions localization/strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ For information please visit https://aka.ms/wslinstall</value>
<value>Failed to create the swap disk in '{}': {}</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageSwapFileConflictsWithDistroVhd" xml:space="preserve">
<value>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.</value>
<comment>{FixedPlaceholder="{}"}{Locked=".wslconfig"}{Locked="swapFile"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageNestedVirtualizationNotSupported" xml:space="preserve">
<value>Nested virtualization is not supported on this machine.</value>
</data>
Expand Down
1 change: 1 addition & 0 deletions src/windows/common/wslutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ static const std::map<HRESULT, LPCWSTR> 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),
Expand Down
50 changes: 50 additions & 0 deletions src/windows/service/exe/LxssUserSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions src/windows/service/inc/wslservice.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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 */")
22 changes: 22 additions & 0 deletions test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading