From fb416747dcfb6e53df5d249d07123989e4ddc796 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 3 Feb 2021 22:32:58 +0100 Subject: api: ensure that device object exists before returning from open/create Some users are seeing errors like this after rebooting from Windows Update: 2021-01-28 18:39:45.220197: [TUN] Creating Wintun interface 2021-01-28 18:39:49.420116: [TUN] [Wintun] CreateAdapter: Creating adapter 2021-01-28 18:39:53.704007: [TUN] [Wintun] OpenDeviceObject: Failed to connect to adapter: The system cannot find the path specified. (Code 0x00000003) 2021-01-28 18:39:53.704007: [TUN] [Wintun] WintunStartSession: Failed to open adapter device object 2021-01-28 18:39:54.097037: [TUN] Unable to create Wintun interface: Error starting session: The system cannot find the path specified. It appears that creation of the device object file might happen asynchronously, so this commit polls for it. Reported-by: Artem Kuroptev Signed-off-by: Jason A. Donenfeld --- api/adapter.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 13 deletions(-) (limited to 'api/adapter.c') diff --git a/api/adapter.c b/api/adapter.c index 6766b9e..298e038 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -178,7 +178,7 @@ IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) return IsOurs; } -static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceObject(_In_opt_z_ const WCHAR *InstanceId) +static _Return_type_success_(return != NULL) WCHAR *GetDeviceObjectFileName(_In_opt_z_ const WCHAR *InstanceId) { ULONG InterfacesLen; DWORD LastError = CM_MapCrToWin32Err( @@ -191,12 +191,11 @@ static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceOb if (LastError != ERROR_SUCCESS) { SetLastError(LOG_ERROR(L"Failed to query associated instances size", LastError)); - return INVALID_HANDLE_VALUE; + return NULL; } WCHAR *Interfaces = Alloc(InterfacesLen * sizeof(WCHAR)); if (!Interfaces) - return INVALID_HANDLE_VALUE; - HANDLE Handle = INVALID_HANDLE_VALUE; + return NULL; LastError = CM_MapCrToWin32Err( CM_Get_Device_Interface_ListW( (GUID *)&GUID_DEVINTERFACE_NET, @@ -208,24 +207,57 @@ static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceOb if (LastError != ERROR_SUCCESS) { LOG_ERROR(L"Failed to get associated instances", LastError); - goto cleanupBuf; + Free(Interfaces); + SetLastError(LastError); + return NULL; } - Handle = CreateFileW( - Interfaces, + return Interfaces; +} + +static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceObject(_In_opt_z_ const WCHAR *InstanceId) +{ + WCHAR *Filename = GetDeviceObjectFileName(InstanceId); + if (!Filename) + return INVALID_HANDLE_VALUE; + HANDLE Handle = CreateFileW( + Filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); - LastError = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to adapter"); -cleanupBuf: - Free(Interfaces); - if (LastError != ERROR_SUCCESS) - SetLastError(LastError); + Free(Filename); + if (Handle == INVALID_HANDLE_VALUE) + LOG_LAST_ERROR(L"Failed to connect to adapter"); return Handle; } +static BOOL +EnsureDeviceObject(_In_opt_z_ const WCHAR *InstanceId) +{ + WCHAR *Filename = GetDeviceObjectFileName(InstanceId); + if (!Filename) + return FALSE; + BOOL Exists = TRUE; + const int Attempts = 100; + for (int i = 0; i < Attempts; ++i) + { + HANDLE Handle = CreateFileW(Filename, 0, 0, NULL, OPEN_EXISTING, 0, NULL); + if (Handle != INVALID_HANDLE_VALUE) + { + CloseHandle(Handle); + goto out; + } + if (i != Attempts - 1) + Sleep(50); + } + Exists = FALSE; +out: + Free(Filename); + return Exists; +} + #define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) static _Return_type_success_(return != FALSE) BOOL @@ -679,7 +711,19 @@ _Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI } Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData); - LastError = Adapter ? ERROR_SUCCESS : LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); + if (!Adapter) + { + LastError = LOG(WINTUN_LOG_ERR, L"Failed to create adapter data"); + goto cleanupDevInfo; + } + + if (!EnsureDeviceObject(Adapter->DevInstanceID)) + { + LastError = LOG_LAST_ERROR(L"Device object file did not appear"); + goto cleanupDevInfo; + } + + LastError = ERROR_SUCCESS; goto cleanupDevInfo; } LastError = ERROR_FILE_NOT_FOUND; @@ -1591,6 +1635,11 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter( else break; } + if (!EnsureDeviceObject(Adapter->DevInstanceID)) + { + LastError = LOG_LAST_ERROR(L"Device object file did not appear"); + goto cleanupTcpipAdapterRegKey; + } LastError = ERROR_SUCCESS; cleanupTcpipAdapterRegKey: -- cgit v1.2.3-59-g8ed1b