aboutsummaryrefslogtreecommitdiffstats
path: root/driver/wintun.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--driver/wintun.c (renamed from wintun.c)389
1 files changed, 210 insertions, 179 deletions
diff --git a/wintun.c b/driver/wintun.c
index 624de2f..ad4b16b 100644
--- a/wintun.c
+++ b/driver/wintun.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <ntifs.h>
@@ -9,7 +9,6 @@
#include <ndis.h>
#include <ntstrsafe.h>
#include "undocumented.h"
-#include "atomic.h"
#pragma warning(disable : 4100) /* unreferenced formal parameter */
#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */
@@ -50,7 +49,7 @@
((((ULONG)(x)&0x000000ff) << 24) | (((ULONG)(x)&0x0000ff00) << 8) | (((ULONG)(x)&0x00ff0000) >> 8) | \
(((ULONG)(x)&0xff000000) >> 24))
#else
-# error "Unable to determine endianess"
+# error "Unable to determine endianness"
#endif
#define TUN_MEMORY_TAG HTONL('wtun')
@@ -100,12 +99,29 @@ typedef struct _TUN_REGISTER_RINGS
} Send, Receive;
} TUN_REGISTER_RINGS;
+#ifdef _WIN64
+typedef struct _TUN_REGISTER_RINGS_32
+{
+ struct
+ {
+ /* Size of the ring */
+ ULONG RingSize;
+
+ /* 32-bit address of client allocated ring */
+ ULONG Ring;
+
+ /* On send: An event created by the client the Wintun signals after it moves the Tail member of the send ring.
+ * On receive: An event created by the client the client will signal when it moves the Tail member of
+ * the receive ring if receive ring is alertable. */
+ ULONG TailMoved;
+ } Send, Receive;
+} TUN_REGISTER_RINGS_32;
+#endif
+
/* Register rings hosted by the client.
* 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
{
@@ -163,10 +179,18 @@ 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);
-static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor;
+/* Binary representation of O:SYD:P(A;;FA;;;SY)(A;;FA;;;BA)S:(ML;;NWNRNX;;;HI) */
+static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor = (SECURITY_DESCRIPTOR *)(__declspec(align(8)) UCHAR[]){
+ 0x01, 0x00, 0x14, 0x90, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x02, 0x00, 0x34, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00,
+ 0x00, 0x20, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00
+};
_IRQL_requires_max_(DISPATCH_LEVEL)
static VOID
@@ -250,7 +274,7 @@ TunSendNetBufferLists(
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
NDIS_STATUS Status;
- if ((Status = NDIS_STATUS_PAUSED, !InterlockedGet(&Ctx->Running)) ||
+ if ((Status = NDIS_STATUS_PAUSED, !ReadAcquire(&Ctx->Running)) ||
(Status = NDIS_STATUS_MEDIA_DISCONNECTED, KeReadStateEvent(&Ctx->Device.Disconnected)))
goto skipNbl;
@@ -258,7 +282,7 @@ TunSendNetBufferLists(
ULONG RingCapacity = Ctx->Device.Send.Capacity;
/* Allocate space for packets in the ring. */
- ULONG RingHead = InterlockedGetU(&Ring->Head);
+ ULONG RingHead = ReadULongAcquire(&Ring->Head);
if (Status = NDIS_STATUS_ADAPTER_NOT_READY, RingHead >= RingCapacity)
goto skipNbl;
@@ -325,7 +349,7 @@ TunSendNetBufferLists(
{
NET_BUFFER_LIST *CompletedNbl = Ctx->Device.Send.ActiveNbls.Head;
Ctx->Device.Send.ActiveNbls.Head = NET_BUFFER_LIST_NEXT_NBL_EX(CompletedNbl);
- InterlockedSetU(&Ring->Tail, TunNblGetOffset(CompletedNbl));
+ WriteULongRelease(&Ring->Tail, TunNblGetOffset(CompletedNbl));
KeSetEvent(Ctx->Device.Send.TailMoved, IO_NETWORK_INCREMENT, FALSE);
NdisMSendNetBufferListsComplete(
Ctx->MiniportAdapterHandle, CompletedNbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
@@ -343,11 +367,11 @@ skipNbl:
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
NdisMSendNetBufferListsComplete(Ctx->MiniportAdapterHandle, NetBufferLists, 0);
updateStatistics:
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount);
}
static MINIPORT_CANCEL_SEND TunCancelSend;
@@ -393,15 +417,25 @@ TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST Net
if (!Ctx->Device.Receive.ActiveNbls.Head)
KeSetEvent(&Ctx->Device.Receive.ActiveNbls.Empty, IO_NO_INCREMENT, FALSE);
KeReleaseInStackQueuedSpinLock(&LockHandle);
- InterlockedSetU(&Ring->Head, TunNblGetOffset(CompletedNbl));
+ WriteULongRelease(&Ring->Head, TunNblGetOffset(CompletedNbl));
+ const MDL *TargetMdl = Ctx->Device.Receive.Mdl;
+ for (MDL *Mdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(CompletedNbl)); Mdl; Mdl = Mdl->Next)
+ {
+ if (MmGetMdlVirtualAddress(Mdl) < MmGetMdlVirtualAddress(TargetMdl) ||
+ (UCHAR *)MmGetMdlVirtualAddress(Mdl) + MmGetMdlByteCount(Mdl) >
+ (UCHAR *)MmGetMdlVirtualAddress(TargetMdl) + MmGetMdlByteCount(TargetMdl))
+ continue;
+ IoFreeMdl(Mdl);
+ break;
+ }
NdisFreeNetBufferList(CompletedNbl);
}
}
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount);
}
_IRQL_requires_max_(PASSIVE_LEVEL)
@@ -419,20 +453,20 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
VOID *Events[] = { &Ctx->Device.Disconnected, Ctx->Device.Receive.TailMoved };
ASSERT(RTL_NUMBER_OF(Events) <= THREAD_WAIT_OBJECTS);
- ULONG RingHead = InterlockedGetU(&Ring->Head);
+ ULONG RingHead = ReadULongAcquire(&Ring->Head);
if (RingHead >= RingCapacity)
goto cleanup;
while (!KeReadStateEvent(&Ctx->Device.Disconnected))
{
/* Get next packet from the ring. */
- ULONG RingTail = InterlockedGetU(&Ring->Tail);
+ ULONG RingTail = ReadULongAcquire(&Ring->Tail);
if (RingHead == RingTail)
{
LARGE_INTEGER SpinStart = KeQueryPerformanceCounter(NULL);
for (;;)
{
- RingTail = InterlockedGetU(&Ring->Tail);
+ RingTail = ReadULongAcquire(&Ring->Tail);
if (RingTail != RingHead)
break;
if (KeReadStateEvent(&Ctx->Device.Disconnected))
@@ -444,16 +478,16 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
}
if (RingHead == RingTail)
{
- InterlockedSet(&Ring->Alertable, TRUE);
- RingTail = InterlockedGetU(&Ring->Tail);
+ WriteRelease(&Ring->Alertable, TRUE);
+ RingTail = ReadULongAcquire(&Ring->Tail);
if (RingHead == RingTail)
{
KeWaitForMultipleObjects(
RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
- InterlockedSet(&Ring->Alertable, FALSE);
+ WriteRelease(&Ring->Alertable, FALSE);
continue;
}
- InterlockedSet(&Ring->Alertable, FALSE);
+ WriteRelease(&Ring->Alertable, FALSE);
KeClearEvent(Ctx->Device.Receive.TailMoved);
}
}
@@ -465,7 +499,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
break;
TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingHead);
- ULONG PacketSize = Packet->Size;
+ ULONG PacketSize = *(volatile ULONG *)&Packet->Size;
if (PacketSize > TUN_MAX_IP_PACKET_SIZE)
break;
@@ -473,6 +507,8 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
if (AlignedPacketSize > RingContent)
break;
+ RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
+
ULONG NblFlags;
USHORT NblProto;
if (PacketSize >= 20 && Packet->Data[0] >> 4 == 4)
@@ -486,14 +522,17 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
NblProto = HTONS(NDIS_ETH_TYPE_IPV6);
}
else
- break;
-
- RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
+ goto skipNbl;
- NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(
- Ctx->NblPool, 0, 0, Ctx->Device.Receive.Mdl, (ULONG)(Packet->Data - (UCHAR *)Ring), PacketSize);
- if (!Nbl)
+ VOID *PacketAddr =
+ (UCHAR *)MmGetMdlVirtualAddress(Ctx->Device.Receive.Mdl) + (ULONG)(Packet->Data - (UCHAR *)Ring);
+ MDL *Mdl = IoAllocateMdl(PacketAddr, PacketSize, FALSE, FALSE, NULL);
+ if (!Mdl)
goto skipNbl;
+ IoBuildPartialMdl(Ctx->Device.Receive.Mdl, Mdl, PacketAddr, PacketSize);
+ NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, 0, 0, Mdl, 0, PacketSize);
+ if (!Nbl)
+ goto cleanupMdl;
Nbl->SourceHandle = Ctx->MiniportAdapterHandle;
NdisSetNblFlag(Nbl, NblFlags);
NET_BUFFER_LIST_INFO(Nbl, NetBufferListFrameType) = (PVOID)NblProto;
@@ -501,7 +540,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
TunNblSetOffsetAndMarkActive(Nbl, RingHead);
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
- if (!InterlockedGet(&Ctx->Running))
+ if (!ReadAcquire(&Ctx->Running))
goto cleanupNbl;
KLOCK_QUEUE_HANDLE LockHandle;
@@ -529,17 +568,19 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
cleanupNbl:
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
NdisFreeNetBufferList(Nbl);
+ cleanupMdl:
+ IoFreeMdl(Mdl);
skipNbl:
- InterlockedIncrement64((LONG64 *)&Ctx->Statistics.ifInDiscards);
+ InterlockedIncrementNoFence64((LONG64 *)&Ctx->Statistics.ifInDiscards);
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
- InterlockedSetU(&Ring->Head, RingHead);
+ WriteULongRelease(&Ring->Head, RingHead);
}
/* Wait for all NBLs to return: 1. To prevent race between proceeding and invalidating ring head. 2. To have
* TunDispatchUnregisterBuffers() implicitly wait before releasing ring MDL used by NBL(s). */
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
cleanup:
- InterlockedSetU(&Ring->Head, MAXULONG);
+ WriteULongRelease(&Ring->Head, MAXULONG);
}
#define IS_POW2(x) ((x) && !((x) & ((x)-1)))
@@ -559,34 +600,52 @@ TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
goto cleanupMutex;
Ctx->Device.OwningFileObject = Stack->FileObject;
- TUN_REGISTER_RINGS *Rrb = Irp->AssociatedIrp.SystemBuffer;
- if (Status = STATUS_INVALID_PARAMETER, Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(*Rrb))
+ TUN_REGISTER_RINGS Rrb;
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(Rrb))
+ NdisMoveMemory(&Rrb, Irp->AssociatedIrp.SystemBuffer, sizeof(Rrb));
+#ifdef _WIN64
+ else if (
+ IoIs32bitProcess(Irp) && Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(TUN_REGISTER_RINGS_32))
+ {
+ TUN_REGISTER_RINGS_32 *Rrb32 = Irp->AssociatedIrp.SystemBuffer;
+ Rrb.Send.RingSize = Rrb32->Send.RingSize;
+ Rrb.Send.Ring = (TUN_RING *)Rrb32->Send.Ring;
+ Rrb.Send.TailMoved = (HANDLE)Rrb32->Send.TailMoved;
+ Rrb.Receive.RingSize = Rrb32->Receive.RingSize;
+ Rrb.Receive.Ring = (TUN_RING *)Rrb32->Receive.Ring;
+ Rrb.Receive.TailMoved = (HANDLE)Rrb32->Receive.TailMoved;
+ }
+#endif
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
goto cleanupResetOwner;
+ }
- Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb->Send.RingSize);
+ Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb.Send.RingSize);
if (Status = STATUS_INVALID_PARAMETER,
(Ctx->Device.Send.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Send.Capacity > TUN_MAX_RING_CAPACITY ||
- !IS_POW2(Ctx->Device.Send.Capacity) || !Rrb->Send.TailMoved || !Rrb->Send.Ring))
+ !IS_POW2(Ctx->Device.Send.Capacity) || !Rrb.Send.TailMoved || !Rrb.Send.Ring))
goto cleanupResetOwner;
if (!NT_SUCCESS(
Status = ObReferenceObjectByHandle(
- Rrb->Send.TailMoved,
+ Rrb.Send.TailMoved,
/* We will not wait on send ring tail moved event. */
EVENT_MODIFY_STATE,
*ExEventObjectType,
- UserMode,
+ Irp->RequestorMode,
&Ctx->Device.Send.TailMoved,
NULL)))
goto cleanupResetOwner;
- Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb->Send.Ring, Rrb->Send.RingSize, FALSE, FALSE, NULL);
+ Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb.Send.Ring, Rrb.Send.RingSize, FALSE, FALSE, NULL);
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Mdl)
goto cleanupSendTailMoved;
try
{
Status = STATUS_INVALID_USER_BUFFER;
- MmProbeAndLockPages(Ctx->Device.Send.Mdl, UserMode, IoWriteAccess);
+ MmProbeAndLockPages(Ctx->Device.Send.Mdl, Irp->RequestorMode, IoWriteAccess);
}
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupSendMdl; }
@@ -595,34 +654,34 @@ TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Ring)
goto cleanupSendUnlockPages;
- Ctx->Device.Send.RingTail = InterlockedGetU(&Ctx->Device.Send.Ring->Tail);
+ Ctx->Device.Send.RingTail = ReadULongAcquire(&Ctx->Device.Send.Ring->Tail);
if (Status = STATUS_INVALID_PARAMETER, Ctx->Device.Send.RingTail >= Ctx->Device.Send.Capacity)
goto cleanupSendUnlockPages;
- Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb->Receive.RingSize);
+ Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb.Receive.RingSize);
if (Status = STATUS_INVALID_PARAMETER,
(Ctx->Device.Receive.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Receive.Capacity > TUN_MAX_RING_CAPACITY ||
- !IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb->Receive.TailMoved || !Rrb->Receive.Ring))
+ !IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb.Receive.TailMoved || !Rrb.Receive.Ring))
goto cleanupSendUnlockPages;
if (!NT_SUCCESS(
Status = ObReferenceObjectByHandle(
- Rrb->Receive.TailMoved,
+ Rrb.Receive.TailMoved,
/* We need to clear receive ring TailMoved event on transition to non-alertable state. */
SYNCHRONIZE | EVENT_MODIFY_STATE,
*ExEventObjectType,
- UserMode,
+ Irp->RequestorMode,
&Ctx->Device.Receive.TailMoved,
NULL)))
goto cleanupSendUnlockPages;
- Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb->Receive.Ring, Rrb->Receive.RingSize, FALSE, FALSE, NULL);
+ Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb.Receive.Ring, Rrb.Receive.RingSize, FALSE, FALSE, NULL);
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Mdl)
goto cleanupReceiveTailMoved;
try
{
Status = STATUS_INVALID_USER_BUFFER;
- MmProbeAndLockPages(Ctx->Device.Receive.Mdl, UserMode, IoWriteAccess);
+ MmProbeAndLockPages(Ctx->Device.Receive.Mdl, Irp->RequestorMode, IoWriteAccess);
}
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupReceiveMdl; }
@@ -709,7 +768,7 @@ TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
}
ZwClose(Ctx->Device.Receive.Thread);
- InterlockedSetU(&Ctx->Device.Send.Ring->Tail, MAXULONG);
+ WriteULongRelease(&Ctx->Device.Send.Ring->Tail, MAXULONG);
KeSetEvent(Ctx->Device.Send.TailMoved, IO_NO_INCREMENT, FALSE);
MmUnlockPages(Ctx->Device.Receive.Mdl);
@@ -724,104 +783,6 @@ TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
_IRQL_requires_max_(PASSIVE_LEVEL)
static VOID
-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;
-
- 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;
-
- 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);
- }
- KeUnstackDetachProcess(&ApcState);
- ObfDereferenceObject(Process);
- }
-cleanup:
- if (HandleTable)
- ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
-}
-
-static NTSTATUS TunInitializeDispatchSecurityDescriptor(VOID)
-{
- NTSTATUS Status;
- SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
- SID LocalSystem = { 0 };
- if (!NT_SUCCESS(Status = RtlInitializeSid(&LocalSystem, &NtAuthority, 1)))
- return Status;
- LocalSystem.SubAuthority[0] = 18;
- struct
- {
- ACL Dacl;
- ACCESS_ALLOWED_ACE AceFiller;
- SID SidFiller;
- } DaclStorage = { 0 };
- if (!NT_SUCCESS(Status = RtlCreateAcl(&DaclStorage.Dacl, sizeof(DaclStorage), ACL_REVISION)))
- return Status;
- ACCESS_MASK AccessMask = GENERIC_ALL;
- RtlMapGenericMask(&AccessMask, IoGetFileObjectGenericMapping());
- if (!NT_SUCCESS(Status = RtlAddAccessAllowedAce(&DaclStorage.Dacl, ACL_REVISION, AccessMask, &LocalSystem)))
- return Status;
- SECURITY_DESCRIPTOR SecurityDescriptor = { 0 };
- if (!NT_SUCCESS(Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)))
- return Status;
- if (!NT_SUCCESS(Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, &DaclStorage.Dacl, FALSE)))
- return Status;
- SecurityDescriptor.Control |= SE_DACL_PROTECTED;
- ULONG RequiredBytes = 0;
- Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, NULL, &RequiredBytes);
- if (Status != STATUS_BUFFER_TOO_SMALL)
- return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status;
- TunDispatchSecurityDescriptor = ExAllocatePoolWithTag(NonPagedPoolNx, RequiredBytes, TUN_MEMORY_TAG);
- if (!TunDispatchSecurityDescriptor)
- return STATUS_INSUFFICIENT_RESOURCES;
- Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, TunDispatchSecurityDescriptor, &RequiredBytes);
- if (!NT_SUCCESS(Status))
- return Status;
- return STATUS_SUCCESS;
-}
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-static VOID
TunProcessNotification(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
if (Create)
@@ -851,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;
@@ -887,10 +847,6 @@ TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
KeLeaveCriticalRegion();
break;
}
- case TUN_IOCTL_FORCE_CLOSE_HANDLES:
- TunForceHandlesClosed(Stack->FileObject->DeviceObject);
- Status = STATUS_SUCCESS;
- break;
}
cleanup:
Irp->IoStatus.Status = Status;
@@ -916,13 +872,88 @@ TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
return NdisDispatchClose(DeviceObject, Irp);
}
+_Dispatch_type_(IRP_MJ_PNP)
+static DRIVER_DISPATCH_PAGED TunDispatchPnp;
+_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;
+
+#pragma warning(suppress : 28175)
+ 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)
+#pragma warning(suppress : 28126)
+ 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
TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
{
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
- InterlockedSet(&Ctx->Running, TRUE);
+ WriteRelease(&Ctx->Running, TRUE);
return NDIS_STATUS_SUCCESS;
}
@@ -933,7 +964,7 @@ TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS Min
{
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
- InterlockedSet(&Ctx->Running, FALSE);
+ WriteRelease(&Ctx->Running, FALSE);
ExReleaseSpinLockExclusive(
&Ctx->TransitionLock,
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
@@ -965,10 +996,10 @@ TunInitializeEx(
/* Leaking memory 'Ctx'. Note: 'Ctx' is freed in TunHaltEx or on failure. */
#pragma warning(suppress : 6014)
- TUN_CTX *Ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*Ctx), TUN_MEMORY_TAG);
+#pragma warning(suppress : 28160)
+ TUN_CTX *Ctx = ExAllocatePoolZero(NonPagedPool, sizeof(*Ctx), TUN_MEMORY_TAG);
if (!Ctx)
return NDIS_STATUS_FAILURE;
- NdisZeroMemory(Ctx, sizeof(*Ctx));
Ctx->MiniportAdapterHandle = MiniportAdapterHandle;
@@ -1075,6 +1106,7 @@ TunInitializeEx(
.RcvLinkSpeed = TUN_LINK_SPEED,
.XmitLinkSpeed = TUN_LINK_SPEED,
.MediaConnectState = MediaConnectStateDisconnected,
+ .MediaDuplexState = MediaDuplexStateFull,
.LookaheadSize = TUN_MAX_IP_PACKET_SIZE,
.MacOptions =
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK,
@@ -1100,10 +1132,6 @@ TunInitializeEx(
MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneralAttributes)))
goto cleanupFreeNblPool;
- /* A miniport driver can call NdisMIndicateStatusEx after setting its
- * registration attributes even if the driver is still in the context
- * of the MiniportInitializeEx function. */
- TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
return NDIS_STATUS_SUCCESS;
cleanupFreeNblPool:
@@ -1127,9 +1155,10 @@ TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction)
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
NdisFreeNetBufferListPool(Ctx->NblPool);
- InterlockedSetPointer(&Ctx->MiniportAdapterHandle, NULL);
-#pragma warning(suppress : 28175)
- InterlockedSetPointer(&Ctx->FunctionalDeviceObject->Reserved, NULL);
+#pragma warning(suppress : 6387)
+ WritePointerNoFence(&Ctx->MiniportAdapterHandle, NULL);
+#pragma warning(suppress : 6387 28175)
+ WritePointerNoFence(&Ctx->FunctionalDeviceObject->Reserved, NULL);
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&TunDispatchCtxGuard, TRUE); /* Ensure above change is visible to all readers. */
ExReleaseResourceLite(&TunDispatchCtxGuard);
@@ -1238,16 +1267,16 @@ TunOidQuery(_Inout_ TUN_CTX *Ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
case OID_GEN_XMIT_OK:
return TunOidQueryWrite32or64(
OidRequest,
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts));
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts));
case OID_GEN_RCV_OK:
return TunOidQueryWrite32or64(
OidRequest,
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts));
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts));
case OID_GEN_STATISTICS:
return TunOidQueryWriteBuf(OidRequest, &Ctx->Statistics, (ULONG)sizeof(Ctx->Statistics));
@@ -1387,18 +1416,19 @@ TunUnload(PDRIVER_OBJECT DriverObject)
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
ExDeleteResourceLite(&TunDispatchCtxGuard);
ExDeleteResourceLite(&TunDispatchDeviceListLock);
- ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
}
DRIVER_INITIALIZE DriverEntry;
+#ifdef ALLOC_PRAGMA
+# pragma alloc_text(INIT, DriverEntry)
+#endif
_Use_decl_annotations_
NTSTATUS
DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
{
NTSTATUS Status;
- if (!NT_SUCCESS(Status = TunInitializeDispatchSecurityDescriptor()))
- return Status;
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
NdisVersion = NdisGetVersion();
if (NdisVersion < NDIS_MINIPORT_VERSION_MIN)
@@ -1451,8 +1481,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;
@@ -1461,6 +1493,5 @@ cleanupNotifier:
cleanupResources:
ExDeleteResourceLite(&TunDispatchCtxGuard);
ExDeleteResourceLite(&TunDispatchDeviceListLock);
- ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
return Status;
}