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 <artem@kuroptev.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									2628412d71
								
							
						
					
					
						commit
						fb416747dc
					
				@ -178,7 +178,7 @@ IsOurAdapter(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData)
 | 
				
			|||||||
    return IsOurs;
 | 
					    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;
 | 
					    ULONG InterfacesLen;
 | 
				
			||||||
    DWORD LastError = CM_MapCrToWin32Err(
 | 
					    DWORD LastError = CM_MapCrToWin32Err(
 | 
				
			||||||
@ -191,12 +191,11 @@ static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceOb
 | 
				
			|||||||
    if (LastError != ERROR_SUCCESS)
 | 
					    if (LastError != ERROR_SUCCESS)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        SetLastError(LOG_ERROR(L"Failed to query associated instances size", LastError));
 | 
					        SetLastError(LOG_ERROR(L"Failed to query associated instances size", LastError));
 | 
				
			||||||
        return INVALID_HANDLE_VALUE;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    WCHAR *Interfaces = Alloc(InterfacesLen * sizeof(WCHAR));
 | 
					    WCHAR *Interfaces = Alloc(InterfacesLen * sizeof(WCHAR));
 | 
				
			||||||
    if (!Interfaces)
 | 
					    if (!Interfaces)
 | 
				
			||||||
        return INVALID_HANDLE_VALUE;
 | 
					        return NULL;
 | 
				
			||||||
    HANDLE Handle = INVALID_HANDLE_VALUE;
 | 
					 | 
				
			||||||
    LastError = CM_MapCrToWin32Err(
 | 
					    LastError = CM_MapCrToWin32Err(
 | 
				
			||||||
        CM_Get_Device_Interface_ListW(
 | 
					        CM_Get_Device_Interface_ListW(
 | 
				
			||||||
            (GUID *)&GUID_DEVINTERFACE_NET,
 | 
					            (GUID *)&GUID_DEVINTERFACE_NET,
 | 
				
			||||||
@ -208,24 +207,57 @@ static _Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE OpenDeviceOb
 | 
				
			|||||||
    if (LastError != ERROR_SUCCESS)
 | 
					    if (LastError != ERROR_SUCCESS)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LOG_ERROR(L"Failed to get associated instances", LastError);
 | 
					        LOG_ERROR(L"Failed to get associated instances", LastError);
 | 
				
			||||||
        goto cleanupBuf;
 | 
					        Free(Interfaces);
 | 
				
			||||||
 | 
					        SetLastError(LastError);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Handle = CreateFileW(
 | 
					    return Interfaces;
 | 
				
			||||||
        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,
 | 
					        GENERIC_READ | GENERIC_WRITE,
 | 
				
			||||||
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
					        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 | 
				
			||||||
        NULL,
 | 
					        NULL,
 | 
				
			||||||
        OPEN_EXISTING,
 | 
					        OPEN_EXISTING,
 | 
				
			||||||
        0,
 | 
					        0,
 | 
				
			||||||
        NULL);
 | 
					        NULL);
 | 
				
			||||||
    LastError = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to adapter");
 | 
					    Free(Filename);
 | 
				
			||||||
cleanupBuf:
 | 
					    if (Handle == INVALID_HANDLE_VALUE)
 | 
				
			||||||
    Free(Interfaces);
 | 
					        LOG_LAST_ERROR(L"Failed to connect to adapter");
 | 
				
			||||||
    if (LastError != ERROR_SUCCESS)
 | 
					 | 
				
			||||||
        SetLastError(LastError);
 | 
					 | 
				
			||||||
    return Handle;
 | 
					    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)
 | 
					#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
 | 
					static _Return_type_success_(return != FALSE) BOOL
 | 
				
			||||||
@ -679,7 +711,19 @@ _Return_type_success_(return != NULL) WINTUN_ADAPTER *WINAPI
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Adapter = CreateAdapterData(Pool, DevInfo, &DevInfoData);
 | 
					        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;
 | 
					        goto cleanupDevInfo;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    LastError = ERROR_FILE_NOT_FOUND;
 | 
					    LastError = ERROR_FILE_NOT_FOUND;
 | 
				
			||||||
@ -1591,6 +1635,11 @@ static _Return_type_success_(return != NULL) WINTUN_ADAPTER *CreateAdapter(
 | 
				
			|||||||
        else
 | 
					        else
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (!EnsureDeviceObject(Adapter->DevInstanceID))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        LastError = LOG_LAST_ERROR(L"Device object file did not appear");
 | 
				
			||||||
 | 
					        goto cleanupTcpipAdapterRegKey;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    LastError = ERROR_SUCCESS;
 | 
					    LastError = ERROR_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cleanupTcpipAdapterRegKey:
 | 
					cleanupTcpipAdapterRegKey:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user