Impersonate caller in ResizeDistribution VHD operations (#40253)

Add scoped wil::CoImpersonateClient() around VHD file operations in ResizeDistribution so that file access is checked against the calling user's permissions rather than running as SYSTEM. Both the grow and shrink paths are covered. VM operations remain as SYSTEM. Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Ben Hillis committed Apr 21, 2026 at 21:58 UTC 3a675eb48c30f20e6eca4e883ac761fd84afbaa4
1 file changed +18 -17
src/windows/service/exe/LxssUserSession.cpp
+18 -17
@@ -1788,47 +1788,48 @@ try
1788 std::lock_guard lock(m_instanceLock);
1789 const wil::unique_hkey lxssKey = s_OpenLxssUserKey();
1790 const auto registration = DistributionRegistration::Open(lxssKey.get(), *DistroGuid);
1791 - LXSS_DISTRO_CONFIGURATION configuration = s_GetDistributionConfiguration(registration);
1791 + const auto configuration = s_GetDistributionConfiguration(registration);
1792 RETURN_HR_IF(WSL_E_WSL2_NEEDED, WI_IsFlagClear(configuration.Flags, LXSS_DISTRO_FLAGS_VM_MODE));
1793
1794 - const auto vhdFilePath = configuration.VhdFilePath;
1795 - if (m_utilityVm && m_utilityVm->IsVhdAttached(vhdFilePath.c_str()))
1794 + const auto& vhdPath = configuration.VhdFilePath;
1795 + if (m_utilityVm && m_utilityVm->IsVhdAttached(vhdPath.c_str()))
1796 {
1797 THROW_HR_WITH_USER_ERROR(WSL_E_DISTRO_NOT_STOPPED, wsl::shared::Localization::MessageVhdInUse());
1798 }
1799
1800 - auto diskHandle = wsl::core::filesystem::OpenVhd(vhdFilePath.c_str(), VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_METAOPS);
1801 - const auto diskSize = wsl::core::filesystem::GetDiskSize(diskHandle.get());
1802 -
1803 - const auto resizingLarger = NewSize > diskSize;
1804 - if (resizingLarger)
1800 + // If growing the VHD, resize the underlying VHD file before resizing the filesystem.
1801 + bool resizingLarger;
1802 {
1806 - wsl::core::filesystem::ResizeExistingVhd(diskHandle.get(), NewSize, RESIZE_VIRTUAL_DISK_FLAG_NONE);
1807 - }
1803 + auto runAsUser = wil::CoImpersonateClient();
1804 + auto diskHandle = wsl::core::filesystem::OpenVhd(vhdPath.c_str(), VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_METAOPS);
1805 + resizingLarger = NewSize > wsl::core::filesystem::GetDiskSize(diskHandle.get());
1806
1809 - diskHandle.reset();
1807 + if (resizingLarger)
1808 + {
1809 + wsl::core::filesystem::ResizeExistingVhd(diskHandle.get(), NewSize, RESIZE_VIRTUAL_DISK_FLAG_NONE);
1810 + }
1811 + }
1812
1813 // Ensure VM exists and attach the VHD.
1814 _CreateVm();
1815 const auto userToken = wsl::windows::common::security::GetUserToken(TokenImpersonation);
1814 - const auto lun = m_utilityVm->AttachDisk(vhdFilePath.c_str(), WslCoreVm::DiskType::VHD, {}, true, userToken.get());
1816 + const auto lun = m_utilityVm->AttachDisk(vhdPath.c_str(), WslCoreVm::DiskType::VHD, {}, true, userToken.get());
1817
1818 // Resize the underlying filesystem.
1819 //
1820 // N.B. Passing zero as the size causes the resize to consume all available space on the block device.
1821 {
1820 - auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { m_utilityVm->EjectVhd(vhdFilePath.c_str()); });
1822 + auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { m_utilityVm->EjectVhd(vhdPath.c_str()); });
1823 m_utilityVm->ResizeDistribution(lun, OutputHandle, resizingLarger ? 0 : NewSize);
1824 }
1825
1826 // If shrinking the VHD, resize the underlying VHD file. This is only supported for .vhdx files.
1827 //
1828 // N.B. RESIZE_VIRTUAL_DISK_FLAG_ALLOW_UNSAFE_VIRTUAL_SIZE is required because vhdmp can't validate that the minimum safe ext4 size.
1827 - if (!resizingLarger &&
1828 - wsl::shared::string::IsEqual(vhdFilePath.extension().c_str(), wsl::windows::common::wslutil::c_vhdxFileExtension, true))
1829 + if (!resizingLarger && wsl::shared::string::IsEqual(vhdPath.extension().c_str(), wsl::windows::common::wslutil::c_vhdxFileExtension, true))
1830 {
1830 - const auto diskHandle =
1831 - wsl::core::filesystem::OpenVhd(vhdFilePath.c_str(), VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_METAOPS);
1831 + auto runAsUser = wil::CoImpersonateClient();
1832 + const auto diskHandle = wsl::core::filesystem::OpenVhd(vhdPath.c_str(), VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_METAOPS);
1833 wsl::core::filesystem::ResizeExistingVhd(diskHandle.get(), NewSize, RESIZE_VIRTUAL_DISK_FLAG_ALLOW_UNSAFE_VIRTUAL_SIZE);
1834 }
1835