diff options
| -rw-r--r-- | api/adapter.c | 147 | ||||
| -rw-r--r-- | api/adapter.h | 2 | ||||
| -rw-r--r-- | api/driver.c | 5 | ||||
| -rw-r--r-- | api/main.c | 1 |
4 files changed, 111 insertions, 44 deletions
diff --git a/api/adapter.c b/api/adapter.c index 14b1ab6..6606514 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -98,42 +98,91 @@ cleanupKey: return RET_ERROR(TRUE, LastError); } -static volatile LONG OrphanThreadIsWorking = FALSE; - -static DWORD -DoOrphanedDeviceCleanup(_In_opt_ LPVOID Ctx) +static VOID +CleanupOrphanedDevices(VOID) { - AdapterCleanupOrphanedDevices(); - OrphanThreadIsWorking = FALSE; - return 0; -} + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + WCHAR InstanceId[MAX_DEVICE_ID_LEN]; -static VOID QueueUpOrphanedDeviceCleanupRoutine(VOID) -{ - if (InterlockedCompareExchange(&OrphanThreadIsWorking, TRUE, FALSE) == FALSE) + /* Step 1) ROOT\WIREGUARD devices that are actually recognized by PNP and probably loading the driver. */ + HANDLE DriverInstallationMutex = NamespaceTakeDriverInstallationMutex(); + if (!DriverInstallationMutex) { - if (!QueueUserWorkItem(DoOrphanedDeviceCleanup, NULL, 0)) - OrphanThreadIsWorking = FALSE; + LOG(WIREGUARD_LOG_ERR, L"Failed to take driver installation mutex"); + goto cleanupSwd; } -} + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"ROOT\\" WIREGUARD_HWID, NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LOG_LAST_ERROR(L"Failed to get adapters"); + goto cleanupReg; + } + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars)) + wcsncpy_s(InstanceId, _countof(InstanceId), L"<unknown>", _TRUNCATE); + if (AdapterRemoveInstance(DevInfo, &DevInfoData)) + LOG(WIREGUARD_LOG_INFO, L"Removed stray adapter %s", InstanceId); + else + LOG_LAST_ERROR(L"Failed to remove stray adapter %s", InstanceId); + } + SetupDiDestroyDeviceInfoList(DevInfo); -VOID AdapterCleanupOrphanedDevices(VOID) -{ + /* Step 2) ROOT\WIREGUARD devices that are not recognized by PNP, which were likely temporary nodes left around by driver installation. */ +cleanupReg: + HKEY EnumKey; + if (RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Enum\\ROOT\\" WIREGUARD_HWID, + 0, + KEY_ENUMERATE_SUB_KEYS, + &EnumKey) != ERROR_SUCCESS) + goto cleanupDriverInstallationMutex; + + for (DWORD Index = 0;;) + { + WCHAR SubKey[MAX_DEVICE_ID_LEN]; + DWORD SubKeyLen = _countof(SubKey); + if (RegEnumKeyExW(EnumKey, Index, SubKey, &SubKeyLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS || + _snwprintf_s(InstanceId, _countof(InstanceId), _TRUNCATE, L"ROOT\\" WIREGUARD_HWID L"\\%s", SubKey) < 0) + break; + + DEVINST DevInst; + if ((CM_Locate_DevNodeW(&DevInst, InstanceId, CM_LOCATE_DEVNODE_PHANTOM) == CR_SUCCESS && + CM_Uninstall_DevNode(DevInst, 0) == CR_SUCCESS) || + RegDeleteTreeW(EnumKey, SubKey) == ERROR_SUCCESS) + LOG(WIREGUARD_LOG_INFO, L"Removed phantom adapter %s", InstanceId); + else + { + ++Index; + LOG_LAST_ERROR(L"Failed to remove phantom adapter %s", InstanceId); + } + } + RegCloseKey(EnumKey); +cleanupDriverInstallationMutex: + NamespaceReleaseMutex(DriverInstallationMutex); + + /* Step 3) SWD\WIREGUARD devices that were left around when the process was forcibly killed. */ +cleanupSwd: HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex(); if (!DeviceInstallationMutex) { - LOG_LAST_ERROR(L"Failed to take device installation mutex"); + LOG(WIREGUARD_LOG_ERR, L"Failed to take device installation mutex"); return; } - - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, 0, NULL, NULL, NULL); + DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WIREGUARD_ENUMERATOR, NULL, 0, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) { LOG_LAST_ERROR(L"Failed to get adapters"); goto cleanupDeviceInstallationMutex; } - - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; for (DWORD EnumIndex = 0;; ++EnumIndex) { if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) @@ -145,30 +194,44 @@ VOID AdapterCleanupOrphanedDevices(VOID) ULONG Status, Code; if (CM_Get_DevNode_Status(&Status, &Code, DevInfoData.DevInst, 0) == CR_SUCCESS && !(Status & DN_HAS_PROBLEM)) continue; - - DEVPROPTYPE PropType; - WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; - SetupDiGetDevicePropertyW( - DevInfo, - &DevInfoData, - &DEVPKEY_WireGuard_Name, - &PropType, - (PBYTE)Name, - MAX_ADAPTER_NAME * sizeof(Name[0]), - NULL, - 0); - if (!AdapterRemoveInstance(DevInfo, &DevInfoData)) - { - LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name); - continue; - } - LOG(WIREGUARD_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name); + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars)) + wcsncpy_s(InstanceId, _countof(InstanceId), L"<unknown>", _TRUNCATE); + if (AdapterRemoveInstance(DevInfo, &DevInfoData)) + LOG(WIREGUARD_LOG_INFO, L"Removed orphaned adapter %s", InstanceId); + else + LOG_LAST_ERROR(L"Failed to remove orphaned adapter %s", InstanceId); } SetupDiDestroyDeviceInfoList(DevInfo); cleanupDeviceInstallationMutex: NamespaceReleaseMutex(DeviceInstallationMutex); } +static volatile LONG OrphanThreadIsWorking = FALSE; + +static DWORD +CleanupOrphanedDevicesThread(_In_opt_ LPVOID Ctx) +{ + CleanupOrphanedDevices(); + InterlockedExchange(&OrphanThreadIsWorking, FALSE); + return 0; +} + +VOID +AdapterCleanupOrphanedDevices(BOOL Background) +{ + if (Background) + { + if (InterlockedCompareExchange(&OrphanThreadIsWorking, TRUE, FALSE) == FALSE) + { + if (!QueueUserWorkItem(CleanupOrphanedDevicesThread, NULL, 0)) + InterlockedExchange(&OrphanThreadIsWorking, FALSE); + } + } + else + CleanupOrphanedDevices(); +} + _Use_decl_annotations_ VOID WINAPI WireGuardCloseAdapter(WIREGUARD_ADAPTER *Adapter) @@ -186,7 +249,7 @@ WireGuardCloseAdapter(WIREGUARD_ADAPTER *Adapter) SetupDiDestroyDeviceInfoList(Adapter->DevInfo); } Free(Adapter); - QueueUpOrphanedDeviceCleanupRoutine(); + AdapterCleanupOrphanedDevices(TRUE); } static _Return_type_success_(return != FALSE) @@ -777,7 +840,7 @@ cleanupDriverInstall: cleanupDeviceInstallationMutex: NamespaceReleaseMutex(DeviceInstallationMutex); cleanup: - QueueUpOrphanedDeviceCleanupRoutine(); + AdapterCleanupOrphanedDevices(TRUE); return RET_ERROR(Adapter, LastError); } @@ -866,7 +929,7 @@ cleanupAdapter: cleanupDeviceInstallationMutex: NamespaceReleaseMutex(DeviceInstallationMutex); cleanup: - QueueUpOrphanedDeviceCleanupRoutine(); + AdapterCleanupOrphanedDevices(TRUE); return RET_ERROR(Adapter, LastError); } diff --git a/api/adapter.h b/api/adapter.h index 9505ccd..5ee1816 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -86,7 +86,7 @@ AdapterGetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId); /** * Cleans up adapters with no attached process. */ -VOID AdapterCleanupOrphanedDevices(VOID); +VOID AdapterCleanupOrphanedDevices(BOOL Background); /** * Removes the specified device instance. diff --git a/api/driver.c b/api/driver.c index c7c914d..646675d 100644 --- a/api/driver.c +++ b/api/driver.c @@ -425,6 +425,9 @@ DriverInstall(HDEVINFO *DevInfoExistingAdaptersForCleanup, SP_DEVINFO_DATA_LIST { static const FILETIME OurDriverDate = WIREGUARD_INF_FILETIME; static const DWORDLONG OurDriverVersion = WIREGUARD_INF_VERSION; + + AdapterCleanupOrphanedDevices(FALSE); + HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) { @@ -608,7 +611,7 @@ BOOL WINAPI WireGuardDeleteDriver(VOID) { DWORD LastError = ERROR_SUCCESS; - AdapterCleanupOrphanedDevices(); + AdapterCleanupOrphanedDevices(FALSE); HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) @@ -104,6 +104,7 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) } EnvInit(); NamespaceInit(); + AdapterCleanupOrphanedDevices(TRUE); break; case DLL_PROCESS_DETACH: |
