diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-06-15 09:44:53 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-06-15 09:44:53 +0200 |
| commit | 6ee142335d0b436f61c951d5cdf8f17b68230fcd (patch) | |
| tree | 6c57da2c9f067446006d80ea1d81fcb94812a709 | |
| parent | fa4637b71df806f499b0a8d38332027d778318f2 (diff) | |
| parent | 94a0a034ca4a538e65c22930f64d9c9205852089 (diff) | |
| download | mullvadvpn-6ee142335d0b436f61c951d5cdf8f17b68230fcd.tar.xz mullvadvpn-6ee142335d0b436f61c951d5cdf8f17b68230fcd.zip | |
Merge branch 'driverlogic-race'
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | windows/driverlogic/src/driverlogic.cpp | 107 |
2 files changed, 102 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6845ea5c59..03b577a220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,8 @@ Line wrap the file at 100 chars. Th - Fix race in network adapter monitor that could result in data corruption and crashes. - Upgrade `miow` dependency to stop daemon from crashing when the named pipes were accessed with `accesschk.exe`. +- Fix race that may rarely occur during install when obtaining the GUID of a newly created TAP + adapter. ## [2020.5-beta1] - 2020-05-18 diff --git a/windows/driverlogic/src/driverlogic.cpp b/windows/driverlogic/src/driverlogic.cpp index 3e482c196f..989ee70cf5 100644 --- a/windows/driverlogic/src/driverlogic.cpp +++ b/windows/driverlogic/src/driverlogic.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "error.h" #include <iostream> +#include <chrono> #include <sstream> #include <string> #include <optional> @@ -28,6 +29,8 @@ constexpr wchar_t DEPRECATED_TAP_HARDWARE_ID[] = L"tap0901"; constexpr wchar_t TAP_HARDWARE_ID[] = L"tapmullvad0901"; constexpr wchar_t TAP_BASE_ALIAS[] = L"Mullvad"; +constexpr std::chrono::milliseconds REGISTRY_GET_TIMEOUT_MS{ 10000 }; + enum ReturnCodes { GENERAL_SUCCESS = 0, @@ -231,6 +234,95 @@ std::wstring GetDeviceInstanceId( return deviceInstanceId.data(); } +bool TryGetRegistryValueTimeout( + HKEY key, + const wchar_t *subkey, + const wchar_t *value, + DWORD flags, + DWORD *type, + void *data, + DWORD *dataSize +) +{ + HANDLE changeEvent = nullptr; + + common::memory::ScopeDestructor scopeDestructor; + scopeDestructor += [changeEvent]() { + if (nullptr != changeEvent) + { + CloseHandle(changeEvent); + } + }; + + auto initialTime = std::chrono::steady_clock::now(); + + for (;;) + { + const auto status = RegGetValueW(key, subkey, value, flags, type, data, dataSize); + + if (ERROR_SUCCESS == status) + { + // We're done + return true; + } + + if (ERROR_FILE_NOT_FOUND != status) + { + THROW_WINDOWS_ERROR(status, "RegGetValueW"); + } + + if (nullptr == changeEvent) + { + changeEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + + if (nullptr == changeEvent) + { + THROW_WINDOWS_ERROR(GetLastError(), "CreateEventW"); + } + } + + // + // Wait for the registry value to be created + // + + auto currentTime = std::chrono::steady_clock::now(); + auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - initialTime); + auto timeDelta = (REGISTRY_GET_TIMEOUT_MS - elapsedTime).count(); + + if (timeDelta <= 0) + { + return false; + } + + const auto notifyResult = RegNotifyChangeKeyValue( + key, + subkey != nullptr, // Watch subkeys + REG_NOTIFY_CHANGE_LAST_SET, + changeEvent, + TRUE + ); + + if (ERROR_SUCCESS != notifyResult) + { + THROW_WINDOWS_ERROR(notifyResult, "RegNotifyChangeKeyValue"); + } + + const auto waitResult = WaitForSingleObject(changeEvent, static_cast<DWORD>(timeDelta)); + if (WAIT_OBJECT_0 == waitResult) + { + // Try again + continue; + } + + if (WAIT_TIMEOUT != waitResult) + { + THROW_WINDOWS_ERROR(GetLastError(), "WaitForSingleObject"); + } + + return false; + } +} + std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) { HKEY hNet = SetupDiOpenDevRegKey( @@ -247,10 +339,15 @@ std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInf THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiOpenDevRegKey"); } + common::memory::ScopeDestructor scopeDestructor; + scopeDestructor += [hNet]() { + RegCloseKey(hNet); + }; + std::vector<wchar_t> instanceId(MAX_PATH + 1); DWORD strSize = static_cast<DWORD>(instanceId.size() * sizeof(wchar_t)); - const auto status = RegGetValueW( + if (!TryGetRegistryValueTimeout( hNet, nullptr, L"NetCfgInstanceId", @@ -258,13 +355,9 @@ std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInf nullptr, instanceId.data(), &strSize - ); - - RegCloseKey(hNet); - - if (ERROR_SUCCESS != status) + )) { - THROW_WINDOWS_ERROR(status, "RegGetValueW"); + THROW_ERROR("Timed out waiting for NetCfgInstanceId."); } return instanceId.data(); |
