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