diff options
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; } |