Skip to content

Commit d8fe141

Browse files
committed
driver: automatically close long-lived handle
There's only one handle that's likely to be open in a long lived way: the tun registration handle. So we can force that closed automatically when the device is about to close, if it's been improperly left open. Other handles will indeed hold up closing, but if those exist, they're a sign of a larger bug elsewhere that should be addressed. On the other hand, tun registration handles might legitimately be open during driver upgrades. This also saves us the trouble of dereferencing a freed FileObject as in the general case. Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent 544fdaa commit d8fe141

File tree

4 files changed

+77
-132
lines changed

4 files changed

+77
-132
lines changed

api/adapter.c

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ WintunCloseAdapter(WINTUN_ADAPTER *Adapter)
191191
if (!Adapter)
192192
return;
193193
Free(Adapter->InterfaceFilename);
194-
if (Adapter->DevInfo)
195-
AdapterForceCloseHandles(Adapter->DevInfo, &Adapter->DevInfoData);
196194
if (Adapter->SwDevice)
197195
SwDeviceClose(Adapter->SwDevice);
198196
if (Adapter->DevInfo)
@@ -896,47 +894,6 @@ WintunOpenAdapter(LPCWSTR Name)
896894
return RET_ERROR(Adapter, LastError);
897895
}
898896

899-
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
900-
901-
_Use_decl_annotations_
902-
BOOL
903-
AdapterForceCloseHandles(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
904-
{
905-
DWORD LastError = ERROR_SUCCESS;
906-
WCHAR InstanceId[MAX_INSTANCE_ID];
907-
DWORD RequiredChars = _countof(InstanceId);
908-
if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars))
909-
{
910-
LOG_LAST_ERROR(L"Failed to get adapter instance ID");
911-
return FALSE;
912-
}
913-
WINTUN_ADAPTER Adapter = { .InterfaceFilename = AdapterGetDeviceObjectFileName(InstanceId) };
914-
if (!Adapter.InterfaceFilename)
915-
{
916-
LOG_LAST_ERROR(L"Failed to get adapter file name");
917-
return FALSE;
918-
}
919-
HANDLE Handle = AdapterOpenDeviceObject(&Adapter);
920-
Free(Adapter.InterfaceFilename);
921-
if (Handle == INVALID_HANDLE_VALUE)
922-
{
923-
LastError = LOG(WINTUN_LOG_ERR, L"Failed to get adapter file object");
924-
return FALSE;
925-
}
926-
DWORD RequiredBytes;
927-
if (DeviceIoControl(Handle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL))
928-
{
929-
LastError = ERROR_SUCCESS;
930-
Sleep(200);
931-
}
932-
else if (GetLastError() == ERROR_NOTHING_TO_TERMINATE)
933-
LastError = ERROR_SUCCESS;
934-
else
935-
LastError = LOG_LAST_ERROR(L"Failed to perform force close ioctl");
936-
CloseHandle(Handle);
937-
return RET_ERROR(TRUE, LastError);
938-
}
939-
940897
_Use_decl_annotations_
941898
BOOL
942899
AdapterRemoveInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)

api/adapter.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,3 @@ AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
135135
_Return_type_success_(return != FALSE)
136136
BOOL
137137
AdapterDisableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
138-
139-
/**
140-
* Force closes all device handles of the specified device instance.
141-
*
142-
* @param DevInfo Device info handle from SetupAPI.
143-
* @param DevInfoData Device info data specifying which device.
144-
*
145-
* @return If the function succeeds, the return value is TRUE. If the
146-
* function fails, the return value is FALSE. To get extended
147-
* error information, call GetLastError.
148-
*/
149-
150-
_Return_type_success_(return != FALSE)
151-
BOOL
152-
AdapterForceCloseHandles(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);

api/driver.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **Disa
6969
((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED))
7070
goto cleanupDeviceNode;
7171

72-
LOG(WINTUN_LOG_INFO, L"Force closing adapter \"%s\" open handles", Name);
73-
if (!AdapterForceCloseHandles(DevInfo, &DeviceNode->Data))
74-
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter \"%s\" open handles", Name);
75-
7672
LOG(WINTUN_LOG_INFO, L"Disabling adapter \"%s\"", Name);
7773
if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data))
7874
{

driver/wintun.c

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ typedef struct _TUN_REGISTER_RINGS_32
122122
* The lpInBuffer and nInBufferSize parameters of DeviceIoControl() must point to an TUN_REGISTER_RINGS struct.
123123
* Client must wait for this IOCTL to finish before adding packets to the ring. */
124124
#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
125-
/* Force close all open handles to allow for updating. */
126-
#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
127125

128126
typedef struct _TUN_CTX
129127
{
@@ -181,7 +179,7 @@ typedef struct _TUN_CTX
181179

182180
static UINT NdisVersion;
183181
static NDIS_HANDLE NdisMiniportDriverHandle;
184-
static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose;
182+
static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose, *NdisDispatchPnp;
185183
static ERESOURCE TunDispatchCtxGuard, TunDispatchDeviceListLock;
186184
static RTL_STATIC_LIST_HEAD(TunDispatchDeviceList);
187185
/* 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)
783781
ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
784782
}
785783

786-
_IRQL_requires_max_(PASSIVE_LEVEL)
787-
static BOOLEAN
788-
TunForceHandlesClosed(_Inout_ DEVICE_OBJECT *DeviceObject)
789-
{
790-
NTSTATUS Status;
791-
PEPROCESS Process;
792-
KAPC_STATE ApcState;
793-
PVOID Object = NULL;
794-
ULONG VerifierFlags = 0;
795-
OBJECT_HANDLE_INFORMATION HandleInfo;
796-
SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL;
797-
BOOLEAN DidClose = FALSE;
798-
799-
MmIsVerifierEnabled(&VerifierFlags);
800-
801-
for (ULONG Size = 0, RequestedSize;
802-
(Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) ==
803-
STATUS_INFO_LENGTH_MISMATCH;
804-
Size = RequestedSize)
805-
{
806-
if (HandleTable)
807-
ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
808-
HandleTable = ExAllocatePoolUninitialized(PagedPool, RequestedSize, TUN_MEMORY_TAG);
809-
if (!HandleTable)
810-
return FALSE;
811-
}
812-
if (!NT_SUCCESS(Status) || !HandleTable)
813-
goto cleanup;
814-
815-
HANDLE CurrentProcessId = PsGetCurrentProcessId();
816-
for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index)
817-
{
818-
FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object;
819-
if (!FileObject || FileObject->Type != 5 || FileObject->DeviceObject != DeviceObject)
820-
continue;
821-
HANDLE ProcessId = HandleTable->Handles[Index].UniqueProcessId;
822-
if (ProcessId == CurrentProcessId)
823-
continue;
824-
Status = PsLookupProcessByProcessId(ProcessId, &Process);
825-
if (!NT_SUCCESS(Status))
826-
continue;
827-
KeStackAttachProcess(Process, &ApcState);
828-
if (!VerifierFlags)
829-
Status = ObReferenceObjectByHandle(
830-
HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo);
831-
if (NT_SUCCESS(Status))
832-
{
833-
if (VerifierFlags || Object == FileObject)
834-
ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode);
835-
if (!VerifierFlags)
836-
ObfDereferenceObject(Object);
837-
DidClose = TRUE;
838-
}
839-
KeUnstackDetachProcess(&ApcState);
840-
ObfDereferenceObject(Process);
841-
}
842-
cleanup:
843-
if (HandleTable)
844-
ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
845-
return DidClose;
846-
}
847-
848784
_IRQL_requires_max_(PASSIVE_LEVEL)
849785
static VOID
850786
TunProcessNotification(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
@@ -876,8 +812,7 @@ static NTSTATUS
876812
TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
877813
{
878814
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
879-
if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS &&
880-
Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_FORCE_CLOSE_HANDLES)
815+
if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS)
881816
return NdisDispatchDeviceControl(DeviceObject, Irp);
882817

883818
SECURITY_SUBJECT_CONTEXT SubjectContext;
@@ -912,9 +847,6 @@ TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
912847
KeLeaveCriticalRegion();
913848
break;
914849
}
915-
case TUN_IOCTL_FORCE_CLOSE_HANDLES:
916-
Status = TunForceHandlesClosed(Stack->FileObject->DeviceObject) ? STATUS_SUCCESS : STATUS_NOTHING_TO_TERMINATE;
917-
break;
918850
}
919851
cleanup:
920852
Irp->IoStatus.Status = Status;
@@ -940,6 +872,79 @@ TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
940872
return NdisDispatchClose(DeviceObject, Irp);
941873
}
942874

875+
_Dispatch_type_(IRP_MJ_PNP)
876+
static DRIVER_DISPATCH_PAGED DispatchPnp;
877+
_Use_decl_annotations_
878+
static NTSTATUS
879+
TunDispatchPnp(DEVICE_OBJECT *DeviceObject, IRP *Irp)
880+
{
881+
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
882+
if (Stack->MinorFunction != IRP_MN_QUERY_REMOVE_DEVICE && Stack->MinorFunction != IRP_MN_SURPRISE_REMOVAL)
883+
goto ndisDispatch;
884+
885+
TUN_CTX *Ctx = DeviceObject->Reserved;
886+
if (!Ctx)
887+
goto ndisDispatch;
888+
889+
ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, TRUE);
890+
if (!Ctx->Device.OwningFileObject || Ctx->Device.OwningFileObject == Stack->FileObject)
891+
goto cleanupLock;
892+
893+
NTSTATUS Status;
894+
PEPROCESS Process;
895+
KAPC_STATE ApcState;
896+
PVOID Object = NULL;
897+
OBJECT_HANDLE_INFORMATION HandleInfo;
898+
SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL;
899+
ULONG VerifierFlags = 0;
900+
901+
for (ULONG Size = 0, RequestedSize;
902+
(Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) ==
903+
STATUS_INFO_LENGTH_MISMATCH;
904+
Size = RequestedSize)
905+
{
906+
if (HandleTable)
907+
ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
908+
HandleTable = ExAllocatePoolUninitialized(PagedPool, RequestedSize, TUN_MEMORY_TAG);
909+
if (!HandleTable)
910+
break;
911+
}
912+
if (!NT_SUCCESS(Status) || !HandleTable)
913+
goto cleanupHandleTable;
914+
915+
MmIsVerifierEnabled(&VerifierFlags);
916+
917+
for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index)
918+
{
919+
FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object;
920+
if (FileObject != Ctx->Device.OwningFileObject)
921+
continue;
922+
Status = PsLookupProcessByProcessId(HandleTable->Handles[Index].UniqueProcessId, &Process);
923+
if (!NT_SUCCESS(Status))
924+
continue;
925+
KeStackAttachProcess(Process, &ApcState);
926+
if (!VerifierFlags)
927+
Status = ObReferenceObjectByHandle(
928+
HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo);
929+
if (NT_SUCCESS(Status))
930+
{
931+
if (VerifierFlags || Object == FileObject)
932+
ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode);
933+
if (!VerifierFlags)
934+
ObfDereferenceObject(Object);
935+
}
936+
KeUnstackDetachProcess(&ApcState);
937+
ObfDereferenceObject(Process);
938+
}
939+
cleanupHandleTable:
940+
if (HandleTable)
941+
ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
942+
cleanupLock:
943+
ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
944+
ndisDispatch:
945+
return NdisDispatchPnp(DeviceObject, Irp);
946+
}
947+
943948
static MINIPORT_RESTART TunRestart;
944949
_Use_decl_annotations_
945950
static NDIS_STATUS
@@ -1474,8 +1479,10 @@ DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
14741479

14751480
NdisDispatchDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
14761481
NdisDispatchClose = DriverObject->MajorFunction[IRP_MJ_CLOSE];
1482+
NdisDispatchPnp = DriverObject->MajorFunction[IRP_MJ_PNP];
14771483
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TunDispatchDeviceControl;
14781484
DriverObject->MajorFunction[IRP_MJ_CLOSE] = TunDispatchClose;
1485+
DriverObject->MajorFunction[IRP_MJ_PNP] = TunDispatchPnp;
14791486

14801487
return STATUS_SUCCESS;
14811488

0 commit comments

Comments
 (0)