aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-07-18 10:25:37 +0000
committerJason A. Donenfeld <Jason@zx2c4.com>2019-07-18 10:34:38 +0000
commit58ce3c50002f348401ea2faaf5574915e078ec63 (patch)
tree8a261a93b9e6af9078a6fdc3fcde58e5847b06b9
parentREADME: clarify ring usage (diff)
downloadwintun-58ce3c50002f348401ea2faaf5574915e078ec63.tar.xz
wintun-58ce3c50002f348401ea2faaf5574915e078ec63.zip
Piggy-back on top of NDIS' device object instead of adding our own
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--.clang-format3
-rw-r--r--README.md2
-rw-r--r--undocumented.h44
-rw-r--r--wintun.c362
-rw-r--r--wintun.vcxproj3
-rw-r--r--wintun.vcxproj.filters5
6 files changed, 86 insertions, 333 deletions
diff --git a/.clang-format b/.clang-format
index 5dbb66e..c7d38ff 100644
--- a/.clang-format
+++ b/.clang-format
@@ -99,7 +99,8 @@ StatementMacros: [
'__drv_allocatesMem',
'__drv_freesMem',
'_Field_size_bytes_',
- '_Function_class_'
+ '_Function_class_',
+ '_Dispatch_type_'
]
TabWidth: '4'
UseTab: Never
diff --git a/README.md b/README.md
index d45f966..d1e5de8 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ Note: due to the use of SHA256 signatures throughout, Windows 7 users who would
## Usage
-After loading the driver and creating a network interface the typical way using [SetupAPI](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/setupapi), open `\\.\Global\WINTUN%d` as Local System, where `%d` is the [LUID](https://docs.microsoft.com/en-us/windows/desktop/api/ifdef/ns-ifdef-_net_luid_lh) index (`NetLuidIndex` member) of the network device.
+After loading the driver and creating a network interface the typical way using [SetupAPI](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/setupapi), open the NDIS device object associated with the PnPInstanceId.
### Ring layout
diff --git a/undocumented.h b/undocumented.h
deleted file mode 100644
index 13547d7..0000000
--- a/undocumented.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#pragma once
-
-#include <wdm.h>
-
-typedef enum
-{
- SystemExtendedHandleInformation = 0x40
-} SYSTEM_INFORMATION_CLASS;
-
-typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
-{
- PVOID Object;
- HANDLE UniqueProcessId;
- HANDLE HandleValue;
- ACCESS_MASK GrantedAccess;
- USHORT CreatorBackTraceIndex;
- USHORT ObjectTypeIndex;
- ULONG HandleAttributes;
- ULONG Reserved;
-} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
-
-typedef struct _SYSTEM_HANDLE_INFORMATION_EX
-{
- ULONG_PTR NumberOfHandles;
- ULONG_PTR Reserved;
- SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[ANYSIZE_ARRAY];
-} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
-
-extern NTSTATUS
-ZwQuerySystemInformation(
- SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- ULONG *ReturnLength);
-
-extern NDIS_HANDLE
-NdisWdfGetAdapterContextFromAdapterHandle(PVOID DeviceExtension);
-
-extern POBJECT_TYPE *IoDeviceObjectType;
diff --git a/wintun.c b/wintun.c
index 862e14a..030f316 100644
--- a/wintun.c
+++ b/wintun.c
@@ -8,7 +8,6 @@
#include <wdmsec.h>
#include <ndis.h>
#include <ntstrsafe.h>
-#include "undocumented.h"
#pragma warning(disable : 4100) /* unreferenced formal parameter */
#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */
@@ -19,9 +18,6 @@
#define NDIS_MINIPORT_VERSION_MIN ((NDIS_MINIPORT_MINIMUM_MAJOR_VERSION << 16) | NDIS_MINIPORT_MINIMUM_MINOR_VERSION)
#define NDIS_MINIPORT_VERSION_MAX ((NDIS_MINIPORT_MAJOR_VERSION << 16) | NDIS_MINIPORT_MINOR_VERSION)
-/* Data device name */
-#define TUN_DEVICE_NAME L"WINTUN%u"
-
#define TUN_VENDOR_NAME "Wintun Tunnel"
#define TUN_VENDOR_ID 0xFFFFFF00
#define TUN_LINK_SPEED 100000000000ULL /* 100gbps */
@@ -110,8 +106,8 @@ typedef struct _TUN_REGISTER_RINGS
typedef enum _TUN_FLAGS
{
- TUN_FLAGS_RUNNING = 1 << 0, /* Toggles between paused and running state */
- TUN_FLAGS_PRESENT = 1 << 1, /* Toggles between removal pending and being present */
+ TUN_FLAGS_RUNNING = 1 << 0, /* Toggles between paused and running state */
+ TUN_FLAGS_PRESENT = 1 << 1, /* Toggles between removal pending and being present */
} TUN_FLAGS;
typedef struct _TUN_CTX
@@ -124,13 +120,11 @@ typedef struct _TUN_CTX
EX_SPIN_LOCK TransitionLock;
NDIS_HANDLE MiniportAdapterHandle; /* This is actually a pointer to NDIS_MINIPORT_BLOCK struct. */
+ DEVICE_OBJECT *FunctionalDeviceObject;
NDIS_STATISTICS_INFO Statistics;
struct
{
- NDIS_HANDLE Handle;
- DEVICE_OBJECT *Object;
- IO_REMOVE_LOCK RemoveLock;
FILE_OBJECT *volatile Owner;
KEVENT Disconnected;
@@ -141,7 +135,8 @@ typedef struct _TUN_CTX
ULONG Capacity;
KEVENT *TailMoved;
KSPIN_LOCK Lock;
- ULONG RingTail; /* We need a private tail offset to keep track of ring allocation without disturbing the client. */
+ ULONG RingTail; /* We need a private tail offset to keep track of ring allocation without disturbing the
+ * client. */
struct
{
NET_BUFFER_LIST *Head, *Tail;
@@ -163,8 +158,8 @@ typedef struct _TUN_CTX
static UINT NdisVersion;
static NDIS_HANDLE NdisMiniportDriverHandle;
-static DRIVER_DISPATCH *NdisDispatchPnP;
-static volatile LONG64 TunAdapterCount;
+static DRIVER_DISPATCH *NdisDispatchPnP, *NdisDispatchDeviceControl, *NdisDispatchClose;
+static ERESOURCE TunCtxDispatchGuard;
static __forceinline ULONG
InterlockedExchangeU(_Inout_ _Interlocked_operand_ ULONG volatile *Target, _In_ ULONG Value)
@@ -444,7 +439,8 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
RingTail = InterlockedGetU(&Ring->Tail);
if (RingHead == RingTail)
{
- KeWaitForMultipleObjects(RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
+ KeWaitForMultipleObjects(
+ RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
InterlockedExchange(&Ring->Alertable, FALSE);
Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
continue;
@@ -526,34 +522,16 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
}
-_IRQL_requires_max_(APC_LEVEL)
-_Must_inspect_result_
-static NTSTATUS
-TunDispatchCreate(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
-{
- NTSTATUS Status;
-
- KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
- LONG Flags = InterlockedGet(&Ctx->Flags);
- if (Status = STATUS_DELETE_PENDING, !(Flags & TUN_FLAGS_PRESENT))
- goto cleanupReleaseSpinLock;
-
- IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
- Status = IoAcquireRemoveLock(&Ctx->Device.RemoveLock, Stack->FileObject);
-
-cleanupReleaseSpinLock:
- ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
- return Status;
-}
-
_IRQL_requires_max_(PASSIVE_LEVEL)
_Must_inspect_result_
static NTSTATUS
-TunDispatchRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
+TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
{
NTSTATUS Status;
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
+ /* TODO TODO TODO: SeCaptureSubjectContext, SeAccessCheck */
+
if (InterlockedCompareExchangePointer(&Ctx->Device.Owner, Stack->FileObject, NULL) != NULL)
return STATUS_ALREADY_INITIALIZED;
@@ -667,7 +645,7 @@ cleanupResetOwner:
_IRQL_requires_max_(PASSIVE_LEVEL)
static void
-TunDispatchUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
+TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
{
if (InterlockedCompareExchangePointer(&Ctx->Device.Owner, NULL, Owner) != Owner)
return;
@@ -699,83 +677,72 @@ TunDispatchUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
ObDereferenceObject(Ctx->Device.Send.TailMoved);
}
-static DRIVER_DISPATCH_PAGED TunDispatch;
+_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
+static DRIVER_DISPATCH TunDispatchDeviceControl;
_Use_decl_annotations_
static NTSTATUS
-TunDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
- NTSTATUS Status;
-
- Irp->IoStatus.Information = 0;
- TUN_CTX *Ctx = NdisGetDeviceReservedExtension(DeviceObject);
- if (Status = STATUS_INVALID_HANDLE, !Ctx)
- goto cleanupCompleteRequest;
-
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
- switch (Stack->MajorFunction)
- {
- case IRP_MJ_CREATE:
- if (!NT_SUCCESS(Status = IoAcquireRemoveLock(&Ctx->Device.RemoveLock, Irp)))
- goto cleanupCompleteRequest;
- Status = TunDispatchCreate(Ctx, Irp);
- IoReleaseRemoveLock(&Ctx->Device.RemoveLock, Irp);
- break;
-
- case IRP_MJ_DEVICE_CONTROL:
- if ((Status = STATUS_INVALID_PARAMETER,
- Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS) ||
- !NT_SUCCESS(Status = IoAcquireRemoveLock(&Ctx->Device.RemoveLock, Irp)))
- goto cleanupCompleteRequest;
- Status = TunDispatchRegisterBuffers(Ctx, Irp);
- IoReleaseRemoveLock(&Ctx->Device.RemoveLock, Irp);
- break;
-
- case IRP_MJ_CLOSE:
- Status = STATUS_SUCCESS;
- TunDispatchUnregisterBuffers(Ctx, Stack->FileObject);
- IoReleaseRemoveLock(&Ctx->Device.RemoveLock, Stack->FileObject);
- break;
-
- default:
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
-
-cleanupCompleteRequest:
+ if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS)
+ return NdisDispatchDeviceControl(DeviceObject, Irp);
+ ExAcquireResourceSharedLite(&TunCtxDispatchGuard, TRUE);
+#pragma warning(suppress : 28175)
+ TUN_CTX *Ctx = DeviceObject->Reserved;
+ NTSTATUS Status = NDIS_STATUS_ADAPTER_NOT_READY;
+ if (Ctx)
+ Status = TunRegisterBuffers(Ctx, Irp);
+ ExReleaseResourceLite(&TunCtxDispatchGuard);
Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
-_Dispatch_type_(IRP_MJ_PNP) static DRIVER_DISPATCH TunDispatchPnP;
+_Dispatch_type_(IRP_MJ_CLOSE)
+static DRIVER_DISPATCH TunDispatchClose;
+_Use_decl_annotations_
+static NTSTATUS
+TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+ ExAcquireResourceSharedLite(&TunCtxDispatchGuard, TRUE);
+#pragma warning(suppress : 28175)
+ TUN_CTX *Ctx = DeviceObject->Reserved;
+ if (Ctx)
+ TunUnregisterBuffers(Ctx, IoGetCurrentIrpStackLocation(Irp)->FileObject);
+ ExReleaseResourceLite(&TunCtxDispatchGuard);
+ return NdisDispatchClose(DeviceObject, Irp);
+}
+
+_Dispatch_type_(IRP_MJ_PNP)
+static DRIVER_DISPATCH TunDispatchPnP;
_Use_decl_annotations_
static NTSTATUS
TunDispatchPnP(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
- IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
- if (Stack->MajorFunction == IRP_MJ_PNP)
- {
+ ExAcquireResourceSharedLite(&TunCtxDispatchGuard, TRUE);
#pragma warning(suppress : 28175)
- TUN_CTX *Ctx = DeviceObject->Reserved;
- if (!Ctx)
- return NdisDispatchPnP(DeviceObject, Irp);
+ TUN_CTX *Ctx = DeviceObject->Reserved;
+ if (!Ctx)
+ goto cleanup;
- switch (Stack->MinorFunction)
- {
- case IRP_MN_QUERY_REMOVE_DEVICE:
- case IRP_MN_SURPRISE_REMOVAL:
- InterlockedAnd(&Ctx->Flags, ~TUN_FLAGS_PRESENT);
- ExReleaseSpinLockExclusive(
- &Ctx->TransitionLock,
- ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
- break;
+ switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction)
+ {
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ case IRP_MN_SURPRISE_REMOVAL:
+ InterlockedAnd(&Ctx->Flags, ~TUN_FLAGS_PRESENT);
+ ExReleaseSpinLockExclusive(
+ &Ctx->TransitionLock,
+ ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
+ break;
- case IRP_MN_CANCEL_REMOVE_DEVICE:
- InterlockedOr(&Ctx->Flags, TUN_FLAGS_PRESENT);
- break;
- }
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ InterlockedOr(&Ctx->Flags, TUN_FLAGS_PRESENT);
+ break;
}
+cleanup:
+ ExReleaseResourceLite(&TunCtxDispatchGuard);
return NdisDispatchPnP(DeviceObject, Irp);
}
@@ -825,63 +792,14 @@ TunInitializeEx(
if (!MiniportAdapterHandle)
return NDIS_STATUS_FAILURE;
-
- /* Register data device first. Having only one device per adapter allows us to store adapter context inside device
- * extension. */
- WCHAR DeviceName[sizeof(L"\\Device\\" TUN_DEVICE_NAME L"4294967295") / sizeof(WCHAR) + 1] = { 0 };
- UNICODE_STRING UnicodeDeviceName;
- TunInitUnicodeString(&UnicodeDeviceName, DeviceName);
- RtlUnicodeStringPrintf(
- &UnicodeDeviceName, L"\\Device\\" TUN_DEVICE_NAME, (ULONG)MiniportInitParameters->NetLuid.Info.NetLuidIndex);
-
- WCHAR SymbolicName[sizeof(L"\\DosDevices\\" TUN_DEVICE_NAME L"4294967295") / sizeof(WCHAR) + 1] = { 0 };
- UNICODE_STRING UnicodeSymbolicName;
- TunInitUnicodeString(&UnicodeSymbolicName, SymbolicName);
- RtlUnicodeStringPrintf(
- &UnicodeSymbolicName,
- L"\\DosDevices\\" TUN_DEVICE_NAME,
- (ULONG)MiniportInitParameters->NetLuid.Info.NetLuidIndex);
-
- static PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION + 1] = {
- TunDispatch, /* IRP_MJ_CREATE */
- NULL, /* IRP_MJ_CREATE_NAMED_PIPE */
- TunDispatch, /* IRP_MJ_CLOSE */
- NULL, /* IRP_MJ_READ */
- NULL, /* IRP_MJ_WRITE */
- NULL, /* IRP_MJ_QUERY_INFORMATION */
- NULL, /* IRP_MJ_SET_INFORMATION */
- NULL, /* IRP_MJ_QUERY_EA */
- NULL, /* IRP_MJ_SET_EA */
- NULL, /* IRP_MJ_FLUSH_BUFFERS */
- NULL, /* IRP_MJ_QUERY_VOLUME_INFORMATION */
- NULL, /* IRP_MJ_SET_VOLUME_INFORMATION */
- NULL, /* IRP_MJ_DIRECTORY_CONTROL */
- NULL, /* IRP_MJ_FILE_SYSTEM_CONTROL */
- TunDispatch, /* IRP_MJ_DEVICE_CONTROL */
- };
- NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceObjectAttributes = {
- .Header = { .Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES,
- .Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1,
- .Size = NDIS_SIZEOF_DEVICE_OBJECT_ATTRIBUTES_REVISION_1 },
- .DeviceName = &UnicodeDeviceName,
- .SymbolicName = &UnicodeSymbolicName,
- .MajorFunctions = DispatchTable,
- .ExtensionSize = sizeof(TUN_CTX),
- .DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL /* Kernel, and SYSTEM: full control. Others: none */
- };
- NDIS_HANDLE DeviceObjectHandle;
- DEVICE_OBJECT *DeviceObject;
- if (!NT_SUCCESS(
- Status = NdisRegisterDeviceEx(
- NdisMiniportDriverHandle, &DeviceObjectAttributes, &DeviceObject, &DeviceObjectHandle)))
+ TUN_CTX *Ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*Ctx), TUN_MEMORY_TAG);
+ if (!Ctx)
return NDIS_STATUS_FAILURE;
+ NdisZeroMemory(Ctx, sizeof(*Ctx));
- TUN_CTX *Ctx = NdisGetDeviceReservedExtension(DeviceObject);
- if (Status = NDIS_STATUS_FAILURE, !Ctx)
- goto cleanupDeregisterDevice;
- DEVICE_OBJECT *FunctionalDeviceObject;
- NdisMGetDeviceProperty(MiniportAdapterHandle, NULL, &FunctionalDeviceObject, NULL, NULL, NULL);
+ Ctx->MiniportAdapterHandle = MiniportAdapterHandle;
+ NdisMGetDeviceProperty(MiniportAdapterHandle, NULL, &Ctx->FunctionalDeviceObject, NULL, NULL, NULL);
/* Reverse engineering indicates that we'd be better off calling
* NdisWdfGetAdapterContextFromAdapterHandle(functional_device),
* which points to our TUN_CTX object directly, but this isn't
@@ -889,12 +807,9 @@ TunInitializeEx(
* this reserved field. Revisit this when we drop support for old
* Windows versions. */
#pragma warning(suppress : 28175)
- ASSERT(!FunctionalDeviceObject->Reserved);
+ ASSERT(!Ctx->FunctionalDeviceObject->Reserved);
#pragma warning(suppress : 28175)
- FunctionalDeviceObject->Reserved = Ctx;
-
- NdisZeroMemory(Ctx, sizeof(*Ctx));
- Ctx->MiniportAdapterHandle = MiniportAdapterHandle;
+ Ctx->FunctionalDeviceObject->Reserved = Ctx;
Ctx->Statistics.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
Ctx->Statistics.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
@@ -909,10 +824,6 @@ TunInitializeEx(
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV |
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT |
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
-
- Ctx->Device.Handle = DeviceObjectHandle;
- Ctx->Device.Object = DeviceObject;
- IoInitializeRemoveLock(&Ctx->Device.RemoveLock, TUN_MEMORY_TAG, 0, 0);
KeInitializeEvent(&Ctx->Device.Disconnected, NotificationEvent, TRUE);
KeInitializeSpinLock(&Ctx->Device.Send.Lock);
@@ -928,7 +839,7 @@ TunInitializeEx(
#pragma warning(suppress : 6014)
Ctx->NblPool = NdisAllocateNetBufferListPool(MiniportAdapterHandle, &NblPoolParameters);
if (Status = NDIS_STATUS_FAILURE, !Ctx->NblPool)
- goto cleanupDeregisterDevice;
+ goto cleanupFreeCtx;
NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES AdapterRegistrationAttributes = {
.Header = { .Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES,
@@ -1015,118 +926,16 @@ TunInitializeEx(
* registration attributes even if the driver is still in the context
* of the MiniportInitializeEx function. */
TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
- InterlockedIncrement64(&TunAdapterCount);
InterlockedOr(&Ctx->Flags, TUN_FLAGS_PRESENT);
return NDIS_STATUS_SUCCESS;
cleanupFreeNblPool:
NdisFreeNetBufferListPool(Ctx->NblPool);
-cleanupDeregisterDevice:
- NdisDeregisterDeviceEx(DeviceObjectHandle);
- return Status;
-}
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-static NTSTATUS
-TunDeviceSetDenyAllDacl(_In_ DEVICE_OBJECT *DeviceObject)
-{
- NTSTATUS Status;
- SECURITY_DESCRIPTOR Sd;
- ACL Acl;
- HANDLE DeviceObjectHandle;
-
- if (!NT_SUCCESS(Status = RtlCreateSecurityDescriptor(&Sd, SECURITY_DESCRIPTOR_REVISION)) ||
- !NT_SUCCESS(Status = RtlCreateAcl(&Acl, sizeof(ACL), ACL_REVISION)) ||
- !NT_SUCCESS(Status = RtlSetDaclSecurityDescriptor(&Sd, TRUE, &Acl, FALSE)) ||
- !NT_SUCCESS(
- Status = ObOpenObjectByPointer(
- DeviceObject,
- OBJ_KERNEL_HANDLE,
- NULL,
- WRITE_DAC,
- *IoDeviceObjectType,
- KernelMode,
- &DeviceObjectHandle)))
- return Status;
-
- Status = ZwSetSecurityObject(DeviceObjectHandle, DACL_SECURITY_INFORMATION, &Sd);
- ZwClose(DeviceObjectHandle);
+cleanupFreeCtx:
+ ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG);
return Status;
}
-_IRQL_requires_max_(PASSIVE_LEVEL)
-static void
-TunForceHandlesClosed(_Inout_ TUN_CTX *Ctx)
-{
- NTSTATUS Status;
- PEPROCESS Process;
- KAPC_STATE ApcState;
- PVOID Object = NULL;
- ULONG VerifierFlags = 0;
- OBJECT_HANDLE_INFORMATION HandleInfo;
- SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL;
-
- 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 = ExAllocatePoolWithTag(PagedPool, RequestedSize, TUN_MEMORY_TAG);
- if (!HandleTable)
- return;
- }
- if (!NT_SUCCESS(Status) || !HandleTable)
- goto cleanup;
-
- for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index)
- {
- /* XXX: We should perhaps first look at table->Handles[i].ObjectTypeIndex, but
- * the value changes lots between NT versions, and it should be implicit anyway. */
- FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object;
- if (!FileObject || FileObject->Type != 5 || FileObject->DeviceObject != Ctx->Device.Object)
- 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);
- }
-cleanup:
- if (HandleTable)
- ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
-}
-
-_IRQL_requires_max_(APC_LEVEL)
-static void
-TunWaitForReferencesToDropToZero(_In_ DEVICE_OBJECT *DeviceObject)
-{
- /* The sleep loop isn't pretty, but we don't have a choice. This is an NDIS bug we're working around. */
- enum
- {
- SleepTime = 50,
- TotalTime = 2 * 60 * 1000,
- MaxTries = TotalTime / SleepTime
- };
-#pragma warning(suppress : 28175)
- for (INT Try = 0; Try < MaxTries && InterlockedGet(&DeviceObject->ReferenceCount); ++Try)
- NdisMSleep(SleepTime);
-}
-
static MINIPORT_HALT TunHaltEx;
_Use_decl_annotations_
static void
@@ -1138,26 +947,14 @@ TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction)
ExReleaseSpinLockExclusive(
&Ctx->TransitionLock,
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
-
- /* Setting a deny-all DACL we prevent userspace to open the data device by symlink after TunForceHandlesClosed(). */
- TunDeviceSetDenyAllDacl(Ctx->Device.Object);
- TunForceHandlesClosed(Ctx);
-
- /* Wait for processing IRP(s) to complete. */
- IoAcquireRemoveLock(&Ctx->Device.RemoveLock, NULL);
- IoReleaseRemoveLockAndWait(&Ctx->Device.RemoveLock, NULL);
NdisFreeNetBufferListPool(Ctx->NblPool);
- /* MiniportAdapterHandle must not be used in TunDispatch(). After TunHaltEx() returns it is invalidated. */
InterlockedExchangePointer(&Ctx->MiniportAdapterHandle, NULL);
-
- ASSERT(InterlockedGet64(&TunAdapterCount) > 0);
- if (InterlockedDecrement64(&TunAdapterCount) <= 0)
- TunWaitForReferencesToDropToZero(Ctx->Device.Object);
-
- /* Deregister data device _after_ we are done using Ctx not to risk an UaF. The Ctx is hosted by device extension.
- */
- NdisDeregisterDeviceEx(Ctx->Device.Handle);
+#pragma warning(suppress : 28175)
+ InterlockedExchangePointer(&Ctx->FunctionalDeviceObject->Reserved, NULL);
+ ExAcquireResourceExclusiveLite(&TunCtxDispatchGuard, TRUE); /* Ensure above change is visible to all readers. */
+ ExReleaseResourceLite(&TunCtxDispatchGuard);
+ ExFreePoolWithTag(Ctx, TUN_MEMORY_TAG);
}
static MINIPORT_SHUTDOWN TunShutdownEx;
@@ -1406,6 +1203,7 @@ static VOID
TunUnload(PDRIVER_OBJECT DriverObject)
{
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
+ ExDeleteResourceLite(&TunCtxDispatchGuard);
}
DRIVER_INITIALIZE DriverEntry;
@@ -1421,6 +1219,8 @@ DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
if (NdisVersion > NDIS_MINIPORT_VERSION_MAX)
NdisVersion = NDIS_MINIPORT_VERSION_MAX;
+ ExInitializeResourceLite(&TunCtxDispatchGuard);
+
NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniport = {
.Header = { .Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS,
.Revision = NdisVersion < NDIS_RUNTIME_VERSION_680
@@ -1457,7 +1257,11 @@ DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
return Status;
NdisDispatchPnP = DriverObject->MajorFunction[IRP_MJ_PNP];
+ NdisDispatchDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
+ NdisDispatchClose = DriverObject->MajorFunction[IRP_MJ_CLOSE];
DriverObject->MajorFunction[IRP_MJ_PNP] = TunDispatchPnP;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TunDispatchDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = TunDispatchClose;
return STATUS_SUCCESS;
}
diff --git a/wintun.vcxproj b/wintun.vcxproj
index 4d72a65..693e3db 100644
--- a/wintun.vcxproj
+++ b/wintun.vcxproj
@@ -176,9 +176,6 @@
<Inf Include="wintun.inf" />
<FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
</ItemGroup>
- <ItemGroup>
- <ClInclude Include="undocumented.h" />
- </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project> \ No newline at end of file
diff --git a/wintun.vcxproj.filters b/wintun.vcxproj.filters
index 5a7e2d9..7077380 100644
--- a/wintun.vcxproj.filters
+++ b/wintun.vcxproj.filters
@@ -29,9 +29,4 @@
<Filter>Source Files</Filter>
</Inf>
</ItemGroup>
- <ItemGroup>
- <ClInclude Include="undocumented.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- </ItemGroup>
</Project> \ No newline at end of file