6289
}
6290
}
6291
6292
- WSL2_TEST_METHOD(CustomModulesVhd)
6292
+ WSL2_TEST_METHOD(CustomVhdsInUserProfile)
6293
{
6294
+ // Regression: HCS fails with E_ACCESSDENIED when user-supplied kernelModules or
6295
+ // systemDistro VHDs live under the user profile and VMWP wasn't granted access.
6296
#ifdef WSL_DEV_INSTALL_PATH
6297
6296
- auto modulesPath = std::format(L"{}\\modules.vhd", WSL_DEV_INSTALL_PATH);
6297
- auto kernelPath = std::format(L"{}\\kernel", WSL_DEV_INSTALL_PATH);
6298
+ const auto modulesPath = std::format(L"{}\\modules.vhd", WSL_DEV_INSTALL_PATH);
6299
+ const auto kernelPath = std::format(L"{}\\kernel", WSL_DEV_INSTALL_PATH);
6300
+ const auto systemDistroPath = std::format(L"{}\\system.vhd", WSL_DEV_INSTALL_PATH);
6301
6302
#else
6300
- auto modulesPath = std::format(L"{}\\tools\\modules.vhd", wsl::windows::common::wslutil::GetMsiPackagePath().value());
6301
- auto kernelPath = std::format(L"{}\\tools\\kernel", wsl::windows::common::wslutil::GetMsiPackagePath().value());
6303
+ const auto installPath = wsl::windows::common::wslutil::GetMsiPackagePath().value();
6304
+ const auto modulesPath = std::format(L"{}\\tools\\modules.vhd", installPath);
6305
+ const auto kernelPath = std::format(L"{}\\tools\\kernel", installPath);
6306
+ const auto systemDistroPath = std::format(L"{}\\system.vhd", installPath);
6307
6308
#endif
6309
6305
- // Create a copy of the modules vhd
6306
- auto testModules = std::filesystem::current_path() / "test-modules.vhd";
6310
+ // Unique folder under %TEMP% so parallel runs don't collide.
6311
+ GUID runId;
6312
+ THROW_IF_FAILED(CoCreateGuid(&runId));
6313
+ const auto testFolder =
6314
+ std::filesystem::temp_directory_path() /
6315
+ std::format(L"wsl-test-vhd-grant-{}", wsl::shared::string::GuidToString<wchar_t>(runId, wsl::shared::string::GuidToStringFlags::None));
6316
+ const auto testModules = testFolder / L"test-modules.vhd";
6317
+ const auto testSystemDistro = testFolder / L"test-system.vhd";
6318
+
6319
+ // Construct the cleanup scope before any filesystem mutations so a failed copy or
6320
+ // VERIFY does not leak the directory across runs.
6321
+ auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
6322
+ std::error_code ignored;
6323
+ std::filesystem::remove_all(testFolder, ignored);
6324
+ });
6325
+
6326
+ std::filesystem::create_directories(testFolder);
6327
6328
VERIFY_IS_TRUE(CopyFile(modulesPath.c_str(), testModules.c_str(), false));
6329
+ VERIFY_IS_TRUE(CopyFile(systemDistroPath.c_str(), testSystemDistro.c_str(), false));
6330
+
6331
+ for (const auto& path : {testModules, testSystemDistro})
6332
+ {
6333
+ auto cmd = std::format(L"icacls.exe \"{}\" /remove Everyone /Q", path.wstring());
6334
+ LxsstuLaunchCommandAndCaptureOutput(cmd.data());
6335
+ }
6336
+
6337
+ WslConfigChange config{LxssGenerateTestConfig(
6338
+ {.kernel = kernelPath, .kernelModules = testModules.wstring(), .systemDistro = testSystemDistro.wstring()})};
6339
+
6340
+ auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"echo OK");
6341
+ VERIFY_ARE_EQUAL(out, L"OK\n");
6342
+ VERIFY_ARE_EQUAL(err, L"");
6343
+ }
6344
+
6345
+ WSL2_TEST_METHOD(CustomVhdsAccessibleViaInheritedAcls)
6346
+ {
6347
+ // Regression: VHDs reachable to VMWP via inherited ACLs must boot even when the
6348
+ // impersonated user lacks WRITE_DAC for HcsGrantVmAccess.
6349
+#ifdef WSL_DEV_INSTALL_PATH
6350
6310
- auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { std::filesystem::remove(testModules); });
6351
+ const auto modulesPath = std::format(L"{}\\modules.vhd", WSL_DEV_INSTALL_PATH);
6352
+ const auto kernelPath = std::format(L"{}\\kernel", WSL_DEV_INSTALL_PATH);
6353
+ const auto systemDistroPath = std::format(L"{}\\system.vhd", WSL_DEV_INSTALL_PATH);
6354
6312
- auto cmd = std::format(
6313
- LR"($acl = Get-Acl '{}' ; $acl.RemoveAccessRuleAll((New-Object System.Security.AccessControl.FileSystemAccessRule(\"Everyone\", \"Read\", \"None\", \"None\", \"Allow\"))); Set-Acl -Path '{}' -AclObject $acl)",
6314
- testModules,
6315
- testModules);
6355
+#else
6356
+ const auto installPath = wsl::windows::common::wslutil::GetMsiPackagePath().value();
6357
+ const auto modulesPath = std::format(L"{}\\tools\\modules.vhd", installPath);
6358
+ const auto kernelPath = std::format(L"{}\\tools\\kernel", installPath);
6359
+ const auto systemDistroPath = std::format(L"{}\\system.vhd", installPath);
6360
6317
- LxsstuLaunchPowershellAndCaptureOutput(cmd);
6361
+#endif
6362
6319
- // Update .wslconfig to point to the copied kernel
6320
- WslConfigChange config{LxssGenerateTestConfig({.kernel = kernelPath, .kernelModules = testModules.wstring()})};
6363
+ WslConfigChange config{LxssGenerateTestConfig({.kernel = kernelPath, .kernelModules = modulesPath, .systemDistro = systemDistroPath})};
6364
6322
- // Validate that WSL starts correctly
6323
- auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"echo OK");
6365
+ // Non-elevated launch so impersonation cannot WRITE_DAC the SYSTEM-owned VHD.
6366
+ const auto nonElevatedToken = GetNonElevatedToken();
6367
+ auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"echo OK", 0, nullptr, nonElevatedToken.get());
6368
VERIFY_ARE_EQUAL(out, L"OK\n");
6369
VERIFY_ARE_EQUAL(err, L"");
6370
}