Skip to content
Merged
39 changes: 36 additions & 3 deletions src/windows/service/exe/WslCoreVm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ RequiredExtraMmioSpaceForPmemFileInMb(_In_ PCWSTR FilePath)
// Convert from bytes to megabytes. Ensure that we don't truncate a 512kb file to 0mb.
return std::max(fileSizeBytes.QuadPart / static_cast<INT64>(_1MB), 1i64);
}

wil::unique_hfile OpenVhdBackingFile(_In_ PCWSTR Path)
{
wil::unique_hfile file{CreateFileW(
Path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)};
THROW_LAST_ERROR_IF(!file);

return file;
}

bool IsBackingVolumeMounted(_In_ HANDLE File)
{
DWORD bytesReturned{};
return DeviceIoControl(File, FSCTL_IS_VOLUME_MOUNTED, nullptr, 0, nullptr, 0, &bytesReturned, nullptr);
}
} // namespace

WslCoreVm::WslCoreVm(_In_ wsl::core::Config&& VmConfig) :
Expand Down Expand Up @@ -990,6 +1005,7 @@ ULONG WslCoreVm::AttachDiskLockHeld(

// Set a scope exit variable to perform cleanup if attaching the disk fails.
DiskStateFlags diskFlags{};
wil::unique_hfile backingFile;
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] {
FreeLun(Lun.value());
if (WI_IsFlagSet(diskFlags, DiskStateFlags::AccessGranted))
Expand Down Expand Up @@ -1047,9 +1063,25 @@ ULONG WslCoreVm::AttachDiskLockHeld(
// Prevent user from launching a distro vhd after manually mounting it; otherwise, return the LUN of the mounted disk.
THROW_HR_IF(WSL_E_USER_VHD_ALREADY_ATTACHED, found->first.User);

return found->second.Lun;
// Check if the lun is still valid. It could be stale if the backing volume is reattached.
if (IsBackingVolumeMounted(found->second.BackingFile.get()))
{
return found->second.Lun;
}

const auto staleLun = found->second.Lun;
wsl::windows::common::hcs::RemoveScsiDisk(m_system.get(), staleLun);
if (WI_IsFlagSet(found->second.Flags, DiskStateFlags::AccessGranted))
{
wsl::windows::common::hcs::RevokeVmAccess(m_machineId.c_str(), found->first.Path.c_str());
}

m_attachedDisks.erase(found);
FreeLun(staleLun);
}

backingFile = OpenVhdBackingFile(Disk);

auto grantDiskAccess = [&]() {
auto runAsUser = wil::impersonate_token(UserToken);
wsl::windows::common::hcs::GrantVmAccess(m_machineId.c_str(), Disk);
Expand Down Expand Up @@ -1084,7 +1116,7 @@ ULONG WslCoreVm::AttachDiskLockHeld(
result, Localization::MessageFailedToAttachDisk(Disk, wsl::windows::common::wslutil::GetSystemErrorString(result)));
}

m_attachedDisks.emplace(AttachedDisk{Type, Disk, IsUserDisk}, DiskState{Lun.value(), {}, diskFlags});
m_attachedDisks.emplace(AttachedDisk{Type, Disk, IsUserDisk}, DiskState{Lun.value(), {}, diskFlags, std::move(backingFile)});
cleanup.release();

return Lun.value();
Expand Down Expand Up @@ -1744,6 +1776,7 @@ std::wstring WslCoreVm::GenerateConfigJson()
// inherited ACLs; otherwise StartComputeSystem will surface E_ACCESSDENIED.
auto attachDisk = [&](PCWSTR path, bool grantVmAccess) {
auto lun = ReserveLun();
auto backingFile = OpenVhdBackingFile(path);
hcs::Attachment disk{};
disk.Type = hcs::AttachmentType::VirtualDisk;
disk.Path = path;
Expand All @@ -1765,7 +1798,7 @@ std::wstring WslCoreVm::GenerateConfigJson()
CATCH_LOG()
}

m_attachedDisks.emplace(AttachedDisk{DiskType::VHD, path, false}, DiskState{lun, {}, diskFlags});
m_attachedDisks.emplace(AttachedDisk{DiskType::VHD, path, false}, DiskState{lun, {}, diskFlags, std::move(backingFile)});
return lun;
};

Expand Down
1 change: 1 addition & 0 deletions src/windows/service/exe/WslCoreVm.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class WslCoreVm
ULONG Lun;
std::map<ULONG, Mount> Mounts;
DiskStateFlags Flags;
wil::unique_hfile BackingFile;
};

struct VirtioFsShare
Expand Down
2 changes: 1 addition & 1 deletion test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ class UnitTests
L"-d DummyBrokenDistro",
L"Failed to attach disk 'C:\\DoesNotExit\\ext4.vhdx' to WSL2: The system cannot find the path "
L"specified. ",
L"Wsl/Service/CreateInstance/MountDisk/HCS/ERROR_PATH_NOT_FOUND");
L"Wsl/Service/CreateInstance/MountDisk/ERROR_PATH_NOT_FOUND");

// Purposefully set an incorrect value type to validate registry error handling.
wsl::windows::common::registry::WriteString(distroKey.get(), nullptr, L"Version", L"Broken");
Expand Down