429 lines
11 KiB
C
429 lines
11 KiB
C
/*++
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
verify.c
|
|
|
|
Abstract:
|
|
|
|
verifer support routines for Ndis wrapper
|
|
|
|
Author:
|
|
|
|
Alireza Dabagh (alid) 8-9-1999
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
8-9-99 alid: initial version
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#define MODULE_NUMBER MODULE_VERIFY
|
|
|
|
LARGE_INTEGER VerifierRequiredTimeSinceBoot = {(ULONG)(40 * 1000 * 1000 * 10), 1};
|
|
|
|
#define VERIFIERFUNC(pfn) ((PDRIVER_VERIFIER_THUNK_ROUTINE)(pfn))
|
|
|
|
const DRIVER_VERIFIER_THUNK_PAIRS ndisVerifierFunctionTable[] =
|
|
{
|
|
{VERIFIERFUNC(NdisAllocateMemory ), VERIFIERFUNC(ndisVerifierAllocateMemory)},
|
|
{VERIFIERFUNC(NdisAllocateMemoryWithTag ), VERIFIERFUNC(ndisVerifierAllocateMemoryWithTag)},
|
|
{VERIFIERFUNC(NdisAllocatePacketPool ), VERIFIERFUNC(ndisVerifierAllocatePacketPool)},
|
|
{VERIFIERFUNC(NdisAllocatePacketPoolEx ), VERIFIERFUNC(ndisVerifierAllocatePacketPoolEx)},
|
|
{VERIFIERFUNC(NdisFreePacketPool ), VERIFIERFUNC(ndisVerifierFreePacketPool)},
|
|
{VERIFIERFUNC(NdisQueryMapRegisterCount ), VERIFIERFUNC(ndisVerifierQueryMapRegisterCount)},
|
|
{VERIFIERFUNC(NdisFreeMemory ), VERIFIERFUNC(ndisVerifierFreeMemory)}
|
|
};
|
|
|
|
|
|
BOOLEAN
|
|
ndisVerifierInitialization(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN cr = FALSE;
|
|
ULONG Level;
|
|
|
|
Status = MmIsVerifierEnabled (&Level);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
ndisVerifierLevel = Level;
|
|
|
|
//
|
|
// combine what we read from registry for ndis with the global flags
|
|
//
|
|
if (ndisFlags & NDIS_GFLAG_INJECT_ALLOCATION_FAILURE)
|
|
ndisVerifierLevel |= DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES;
|
|
|
|
if (ndisFlags & NDIS_GFLAG_SPECIAL_POOL_ALLOCATION)
|
|
ndisVerifierLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
|
|
|
|
Status = MmAddVerifierThunks ((VOID *) ndisVerifierFunctionTable,
|
|
sizeof(ndisVerifierFunctionTable));
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
InitializeListHead(&ndisMiniportTrackAllocList);
|
|
InitializeListHead(&ndisDriverTrackAllocList);
|
|
INITIALIZE_SPIN_LOCK(&ndisTrackMemLock);
|
|
cr = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return cr;
|
|
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisVerifierAllocateMemory(
|
|
OUT PVOID * VirtualAddress,
|
|
IN UINT Length,
|
|
IN UINT MemoryFlags,
|
|
IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
|
|
)
|
|
{
|
|
PVOID Address;
|
|
|
|
#if DBG
|
|
if ((ndisFlags & NDIS_GFLAG_WARNING_LEVEL_MASK) >= NDIS_GFLAG_WARN_LEVEL_1)
|
|
{
|
|
DbgPrint("Driver is using NdisAllocateMemory instead of NdisAllocateMemoryWithTag\n");
|
|
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
|
|
{
|
|
Length += sizeof(NDIS_TRACK_MEM);
|
|
}
|
|
|
|
ndisFlags |= NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION;
|
|
ndisMiniportTrackAlloc = NULL;
|
|
ndisDriverTrackAlloc = NULL;
|
|
|
|
if (ndisVerifierInjectResourceFailure(TRUE))
|
|
{
|
|
Address = NULL;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (MemoryFlags != 0)
|
|
{
|
|
NdisAllocateMemory(
|
|
&Address,
|
|
Length,
|
|
MemoryFlags,
|
|
HighestAcceptableAddress);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
|
|
{
|
|
Address = ExAllocatePoolWithTagPriority(
|
|
NonPagedPool,
|
|
Length,
|
|
NDIS_TAG_ALLOC_MEM_VERIFY_ON,
|
|
NormalPoolPrioritySpecialPoolOverrun); // most common problem
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
Address = ALLOC_FROM_POOL(Length, NDIS_TAG_ALLOC_MEM);
|
|
}
|
|
}
|
|
}
|
|
|
|
*VirtualAddress = Address;
|
|
|
|
if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
|
|
{
|
|
*VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
|
|
}
|
|
|
|
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisVerifierAllocateMemoryWithTag(
|
|
OUT PVOID * VirtualAddress,
|
|
IN UINT Length,
|
|
IN ULONG Tag
|
|
)
|
|
{
|
|
|
|
PVOID Caller, CallersCaller;
|
|
PVOID Address;
|
|
PNDIS_TRACK_MEM TrackMem;
|
|
KIRQL OldIrql;
|
|
|
|
|
|
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
|
|
{
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
Length += sizeof(NDIS_TRACK_MEM);
|
|
}
|
|
|
|
if (ndisVerifierInjectResourceFailure(TRUE))
|
|
{
|
|
Address = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (ndisVerifierLevel & DRIVER_VERIFIER_SPECIAL_POOLING)
|
|
{
|
|
Address = ExAllocatePoolWithTagPriority(
|
|
NonPagedPool,
|
|
Length,
|
|
Tag,
|
|
NormalPoolPrioritySpecialPoolOverrun); // most common problem
|
|
}
|
|
else
|
|
{
|
|
Address = ALLOC_FROM_POOL(Length, Tag);
|
|
}
|
|
}
|
|
|
|
if ((Address != NULL) && (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION))
|
|
{
|
|
*VirtualAddress = (PVOID)((PUCHAR)Address + sizeof(NDIS_TRACK_MEM));
|
|
TrackMem = (PNDIS_TRACK_MEM)Address;
|
|
RtlZeroMemory(TrackMem, sizeof(NDIS_TRACK_MEM));
|
|
TrackMem->Tag = Tag;
|
|
TrackMem->Length = Length;
|
|
TrackMem->Caller = Caller;
|
|
TrackMem->CallersCaller = CallersCaller;
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
|
|
if (ndisMiniportTrackAlloc)
|
|
{
|
|
//
|
|
// charge it against miniport
|
|
//
|
|
InsertHeadList(&ndisMiniportTrackAllocList, &TrackMem->List);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// charge it against driver
|
|
//
|
|
InsertHeadList(&ndisDriverTrackAllocList, &TrackMem->List);
|
|
|
|
}
|
|
RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
|
|
}
|
|
else
|
|
{
|
|
*VirtualAddress = Address;
|
|
}
|
|
|
|
return (*VirtualAddress == NULL) ? NDIS_STATUS_FAILURE : NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisVerifierAllocatePacketPool(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors,
|
|
IN UINT ProtocolReservedLength
|
|
)
|
|
{
|
|
PVOID Caller, CallersCaller;
|
|
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
|
|
if (ndisVerifierInjectResourceFailure(TRUE))
|
|
{
|
|
*PoolHandle = NULL;
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
NdisAllocatePacketPool(
|
|
Status,
|
|
PoolHandle,
|
|
NumberOfDescriptors,
|
|
ProtocolReservedLength);
|
|
if (*Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PNDIS_PKT_POOL Pool = *PoolHandle;
|
|
|
|
Pool->Allocator = Caller;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ndisVerifierAllocatePacketPoolEx(
|
|
OUT PNDIS_STATUS Status,
|
|
OUT PNDIS_HANDLE PoolHandle,
|
|
IN UINT NumberOfDescriptors,
|
|
IN UINT NumberOfOverflowDescriptors,
|
|
IN UINT ProtocolReservedLength
|
|
)
|
|
{
|
|
PVOID Caller, CallersCaller;
|
|
|
|
RtlGetCallersAddress(&Caller, &CallersCaller);
|
|
|
|
if (ndisVerifierInjectResourceFailure(TRUE))
|
|
{
|
|
*PoolHandle = NULL;
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
NdisAllocatePacketPoolEx(
|
|
Status,
|
|
PoolHandle,
|
|
NumberOfDescriptors,
|
|
NumberOfOverflowDescriptors,
|
|
ProtocolReservedLength);
|
|
if (*Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PNDIS_PKT_POOL Pool = *PoolHandle;
|
|
|
|
Pool->Allocator = Caller;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ndisVerifierFreePacketPool(
|
|
IN NDIS_HANDLE PoolHandle
|
|
)
|
|
{
|
|
ndisFreePacketPool(PoolHandle, TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
ndisVerifierInjectResourceFailure(
|
|
BOOLEAN fDelayFailure
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function determines whether a resource allocation should be
|
|
deliberately failed. This may be a pool allocation, MDL creation,
|
|
system PTE allocation, etc.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the allocation should be failed. FALSE otherwise.
|
|
|
|
Environment:
|
|
|
|
Kernel mode. DISPATCH_LEVEL or below.
|
|
|
|
--*/
|
|
|
|
{
|
|
LARGE_INTEGER CurrentTime;
|
|
|
|
if (!(ndisVerifierLevel & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (fDelayFailure)
|
|
{
|
|
//
|
|
// Don't fail any requests in the first 7 or 8 minutes as we want to
|
|
// give the system enough time to boot.
|
|
//
|
|
|
|
if (VerifierSystemSufficientlyBooted == FALSE)
|
|
{
|
|
KeQuerySystemTime (&CurrentTime);
|
|
if (CurrentTime.QuadPart > KeBootTime.QuadPart + VerifierRequiredTimeSinceBoot.QuadPart)
|
|
{
|
|
VerifierSystemSufficientlyBooted = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fDelayFailure || (VerifierSystemSufficientlyBooted == TRUE))
|
|
{
|
|
|
|
KeQueryTickCount(&CurrentTime);
|
|
|
|
if ((CurrentTime.LowPart & 0x7) == 0)
|
|
{
|
|
//
|
|
// Deliberately fail this request.
|
|
//
|
|
InterlockedIncrement(&ndisVeriferFailedAllocations);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisVerifierQueryMapRegisterCount(
|
|
IN NDIS_INTERFACE_TYPE BusType,
|
|
OUT PUINT MapRegisterCount
|
|
)
|
|
{
|
|
#if DBG
|
|
DbgPrint("NdisQueryMapRegisterCount: Driver is using an obsolete API.\n");
|
|
if (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING)
|
|
DbgBreakPoint();
|
|
#endif
|
|
|
|
*MapRegisterCount = 0;
|
|
return NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
VOID
|
|
ndisVerifierFreeMemory(
|
|
IN PVOID VirtualAddress,
|
|
IN UINT Length,
|
|
IN UINT MemoryFlags
|
|
)
|
|
|
|
{
|
|
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
|
|
{
|
|
PNDIS_TRACK_MEM TrackMem;
|
|
KIRQL OldIrql;
|
|
|
|
Length += sizeof(NDIS_TRACK_MEM);
|
|
VirtualAddress = (PVOID)((PUCHAR)VirtualAddress - sizeof(NDIS_TRACK_MEM));
|
|
TrackMem = (PNDIS_TRACK_MEM)VirtualAddress;
|
|
|
|
if(!(ndisFlags & NDIS_GFLAG_ABORT_TRACK_MEM_ALLOCATION))
|
|
{
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisTrackMemLock, &OldIrql);
|
|
RemoveEntryList(&TrackMem->List);
|
|
RELEASE_SPIN_LOCK(&ndisTrackMemLock, OldIrql);
|
|
}
|
|
}
|
|
|
|
NdisFreeMemory(VirtualAddress, Length, MemoryFlags);
|
|
}
|
|
|