diff --git a/api/adapter.c b/api/adapter.c index b71032a..6aa6c21 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -191,8 +191,6 @@ WintunCloseAdapter(WINTUN_ADAPTER *Adapter) if (!Adapter) return; Free(Adapter->InterfaceFilename); - if (Adapter->DevInfo) - AdapterForceCloseHandles(Adapter->DevInfo, &Adapter->DevInfoData); if (Adapter->SwDevice) SwDeviceClose(Adapter->SwDevice); if (Adapter->DevInfo) @@ -896,47 +894,6 @@ cleanup: return RET_ERROR(Adapter, LastError); } -#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) - -_Use_decl_annotations_ -BOOL -AdapterForceCloseHandles(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) -{ - DWORD LastError = ERROR_SUCCESS; - WCHAR InstanceId[MAX_INSTANCE_ID]; - DWORD RequiredChars = _countof(InstanceId); - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars)) - { - LOG_LAST_ERROR(L"Failed to get adapter instance ID"); - return FALSE; - } - WINTUN_ADAPTER Adapter = { .InterfaceFilename = AdapterGetDeviceObjectFileName(InstanceId) }; - if (!Adapter.InterfaceFilename) - { - LOG_LAST_ERROR(L"Failed to get adapter file name"); - return FALSE; - } - HANDLE Handle = AdapterOpenDeviceObject(&Adapter); - Free(Adapter.InterfaceFilename); - if (Handle == INVALID_HANDLE_VALUE) - { - LastError = LOG(WINTUN_LOG_ERR, L"Failed to get adapter file object"); - return FALSE; - } - DWORD RequiredBytes; - if (DeviceIoControl(Handle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL)) - { - LastError = ERROR_SUCCESS; - Sleep(200); - } - else if (GetLastError() == ERROR_NOTHING_TO_TERMINATE) - LastError = ERROR_SUCCESS; - else - LastError = LOG_LAST_ERROR(L"Failed to perform force close ioctl"); - CloseHandle(Handle); - return RET_ERROR(TRUE, LastError); -} - _Use_decl_annotations_ BOOL AdapterRemoveInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) diff --git a/api/adapter.h b/api/adapter.h index ec84d70..567ee82 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -135,18 +135,3 @@ AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); _Return_type_success_(return != FALSE) BOOL AdapterDisableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); - -/** - * Force closes all device handles of the specified device instance. - * - * @param DevInfo Device info handle from SetupAPI. - * @param DevInfoData Device info data specifying which device. - * - * @return If the function succeeds, the return value is TRUE. If the - * function fails, the return value is FALSE. To get extended - * error information, call GetLastError. - */ - -_Return_type_success_(return != FALSE) -BOOL -AdapterForceCloseHandles(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData); diff --git a/api/driver.c b/api/driver.c index 3fb4909..172749f 100644 --- a/api/driver.c +++ b/api/driver.c @@ -69,10 +69,6 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED)) goto cleanupDeviceNode; - LOG(WINTUN_LOG_INFO, L"Force closing adapter \"%s\" open handles", Name); - if (!AdapterForceCloseHandles(DevInfo, &DeviceNode->Data)) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter \"%s\" open handles", Name); - LOG(WINTUN_LOG_INFO, L"Disabling adapter \"%s\"", Name); if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data)) { diff --git a/driver/wintun.c b/driver/wintun.c index 2e740e2..1969854 100644 --- a/driver/wintun.c +++ b/driver/wintun.c @@ -122,8 +122,6 @@ typedef struct _TUN_REGISTER_RINGS_32 * The lpInBuffer and nInBufferSize parameters of DeviceIoControl() must point to an TUN_REGISTER_RINGS struct. * Client must wait for this IOCTL to finish before adding packets to the ring. */ #define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) -/* Force close all open handles to allow for updating. */ -#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) typedef struct _TUN_CTX { @@ -181,7 +179,7 @@ typedef struct _TUN_CTX static UINT NdisVersion; static NDIS_HANDLE NdisMiniportDriverHandle; -static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose; +static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose, *NdisDispatchPnp; static ERESOURCE TunDispatchCtxGuard, TunDispatchDeviceListLock; static RTL_STATIC_LIST_HEAD(TunDispatchDeviceList); /* Binary representation of O:SYD:P(A;;FA;;;SY)(A;;FA;;;BA)S:(ML;;NWNRNX;;;HI) */ @@ -783,68 +781,6 @@ TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner) ExReleaseResourceLite(&Ctx->Device.RegistrationLock); } -_IRQL_requires_max_(PASSIVE_LEVEL) -static BOOLEAN -TunForceHandlesClosed(_Inout_ DEVICE_OBJECT *DeviceObject) -{ - NTSTATUS Status; - PEPROCESS Process; - KAPC_STATE ApcState; - PVOID Object = NULL; - ULONG VerifierFlags = 0; - OBJECT_HANDLE_INFORMATION HandleInfo; - SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL; - BOOLEAN DidClose = FALSE; - - MmIsVerifierEnabled(&VerifierFlags); - - for (ULONG Size = 0, RequestedSize; - (Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) == - STATUS_INFO_LENGTH_MISMATCH; - Size = RequestedSize) - { - if (HandleTable) - ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); - HandleTable = ExAllocatePoolUninitialized(PagedPool, RequestedSize, TUN_MEMORY_TAG); - if (!HandleTable) - return FALSE; - } - if (!NT_SUCCESS(Status) || !HandleTable) - goto cleanup; - - HANDLE CurrentProcessId = PsGetCurrentProcessId(); - for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index) - { - FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object; - if (!FileObject || FileObject->Type != 5 || FileObject->DeviceObject != DeviceObject) - continue; - HANDLE ProcessId = HandleTable->Handles[Index].UniqueProcessId; - if (ProcessId == CurrentProcessId) - continue; - Status = PsLookupProcessByProcessId(ProcessId, &Process); - if (!NT_SUCCESS(Status)) - continue; - KeStackAttachProcess(Process, &ApcState); - if (!VerifierFlags) - Status = ObReferenceObjectByHandle( - HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo); - if (NT_SUCCESS(Status)) - { - if (VerifierFlags || Object == FileObject) - ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode); - if (!VerifierFlags) - ObfDereferenceObject(Object); - DidClose = TRUE; - } - KeUnstackDetachProcess(&ApcState); - ObfDereferenceObject(Process); - } -cleanup: - if (HandleTable) - ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); - return DidClose; -} - _IRQL_requires_max_(PASSIVE_LEVEL) static VOID TunProcessNotification(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) @@ -876,8 +812,7 @@ static NTSTATUS TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp) { IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp); - if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS && - Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_FORCE_CLOSE_HANDLES) + if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS) return NdisDispatchDeviceControl(DeviceObject, Irp); SECURITY_SUBJECT_CONTEXT SubjectContext; @@ -912,9 +847,6 @@ TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp) KeLeaveCriticalRegion(); break; } - case TUN_IOCTL_FORCE_CLOSE_HANDLES: - Status = TunForceHandlesClosed(Stack->FileObject->DeviceObject) ? STATUS_SUCCESS : STATUS_NOTHING_TO_TERMINATE; - break; } cleanup: Irp->IoStatus.Status = Status; @@ -940,6 +872,79 @@ TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp) return NdisDispatchClose(DeviceObject, Irp); } +_Dispatch_type_(IRP_MJ_PNP) +static DRIVER_DISPATCH_PAGED DispatchPnp; +_Use_decl_annotations_ +static NTSTATUS +TunDispatchPnp(DEVICE_OBJECT *DeviceObject, IRP *Irp) +{ + IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp); + if (Stack->MinorFunction != IRP_MN_QUERY_REMOVE_DEVICE && Stack->MinorFunction != IRP_MN_SURPRISE_REMOVAL) + goto ndisDispatch; + + TUN_CTX *Ctx = DeviceObject->Reserved; + if (!Ctx) + goto ndisDispatch; + + ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, TRUE); + if (!Ctx->Device.OwningFileObject || Ctx->Device.OwningFileObject == Stack->FileObject) + goto cleanupLock; + + NTSTATUS Status; + PEPROCESS Process; + KAPC_STATE ApcState; + PVOID Object = NULL; + OBJECT_HANDLE_INFORMATION HandleInfo; + SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL; + ULONG VerifierFlags = 0; + + for (ULONG Size = 0, RequestedSize; + (Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) == + STATUS_INFO_LENGTH_MISMATCH; + Size = RequestedSize) + { + if (HandleTable) + ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); + HandleTable = ExAllocatePoolUninitialized(PagedPool, RequestedSize, TUN_MEMORY_TAG); + if (!HandleTable) + break; + } + if (!NT_SUCCESS(Status) || !HandleTable) + goto cleanupHandleTable; + + MmIsVerifierEnabled(&VerifierFlags); + + for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index) + { + FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object; + if (FileObject != Ctx->Device.OwningFileObject) + continue; + Status = PsLookupProcessByProcessId(HandleTable->Handles[Index].UniqueProcessId, &Process); + if (!NT_SUCCESS(Status)) + continue; + KeStackAttachProcess(Process, &ApcState); + if (!VerifierFlags) + Status = ObReferenceObjectByHandle( + HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo); + if (NT_SUCCESS(Status)) + { + if (VerifierFlags || Object == FileObject) + ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode); + if (!VerifierFlags) + ObfDereferenceObject(Object); + } + KeUnstackDetachProcess(&ApcState); + ObfDereferenceObject(Process); + } +cleanupHandleTable: + if (HandleTable) + ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG); +cleanupLock: + ExReleaseResourceLite(&Ctx->Device.RegistrationLock); +ndisDispatch: + return NdisDispatchPnp(DeviceObject, Irp); +} + static MINIPORT_RESTART TunRestart; _Use_decl_annotations_ static NDIS_STATUS @@ -1474,8 +1479,10 @@ DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath) NdisDispatchDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; NdisDispatchClose = DriverObject->MajorFunction[IRP_MJ_CLOSE]; + NdisDispatchPnp = DriverObject->MajorFunction[IRP_MJ_PNP]; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TunDispatchDeviceControl; DriverObject->MajorFunction[IRP_MJ_CLOSE] = TunDispatchClose; + DriverObject->MajorFunction[IRP_MJ_PNP] = TunDispatchPnp; return STATUS_SUCCESS;