From b2374dadb6cbd8c9c745041f5c3665cf4d270dff Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 15 Dec 2020 21:10:39 +0100 Subject: [PATCH] driver: use IoAllocateMdl without being too clever Windows 7 doesn't like our trick of sticking MDLs into the NBL context area. So we do things more traditionally, by allocating an MDL with IoAllocateMdl and freeing it with IoFreeMdl. This means that we have to keep track of the MDL between allocation and free time, and we don't have any more miniport reserved pointers left in the NBL. So instead we walk the MdlChain field of the first NB, and free the one that has an address living inside of the non-partial MDL. Signed-off-by: Jason A. Donenfeld --- driver/wintun.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/driver/wintun.c b/driver/wintun.c index a762dcb..b833663 100644 --- a/driver/wintun.c +++ b/driver/wintun.c @@ -412,6 +412,16 @@ TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST Net KeSetEvent(&Ctx->Device.Receive.ActiveNbls.Empty, IO_NO_INCREMENT, FALSE); KeReleaseInStackQueuedSpinLock(&LockHandle); 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); } } @@ -507,20 +517,17 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) break; RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity); - MDL *Mdl; - NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, sizeof(*Mdl), 0, NULL, 0, 0); - if (!Nbl) + MDL *Mdl = IoAllocateMdl(NULL, PacketSize, FALSE, FALSE, NULL); + if (!Mdl) goto skipNbl; - Mdl = (MDL *)NET_BUFFER_LIST_CONTEXT_DATA_START(Nbl); IoBuildPartialMdl( Ctx->Device.Receive.Mdl, Mdl, (UCHAR *)MmGetMdlVirtualAddress(Ctx->Device.Receive.Mdl) + (ULONG)(Packet->Data - (UCHAR *)Ring), PacketSize); - NET_BUFFER *Nb = NET_BUFFER_LIST_FIRST_NB(Nbl); - NET_BUFFER_FIRST_MDL(Nb) = NET_BUFFER_CURRENT_MDL(Nb) = Mdl; - NET_BUFFER_DATA_LENGTH(Nb) = PacketSize; - NET_BUFFER_DATA_OFFSET(Nb) = NET_BUFFER_CURRENT_MDL_OFFSET(Nb) = 0; + 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; @@ -556,6 +563,8 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) cleanupNbl: ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); NdisFreeNetBufferList(Nbl); + cleanupMdl: + IoFreeMdl(Mdl); skipNbl: InterlockedIncrementNoFence64((LONG64 *)&Ctx->Statistics.ifInDiscards); KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);