Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

810 lines
22 KiB

/******************************Module*Header*******************************\
* Module Name: verifier.cxx
*
* GRE DriverVerifier support.
*
* If DriverVerifier is enabled for a particular component, the loader will
* substitute VerifierEngAllocMem for EngAllocMem, etc. The VerifierEngXX
* functions will help test the robustness of components that use EngXX calls
* by injecting random failures and using special pool (i.e., test low-mem
* behavior and check for buffer overruns).
*
* See ntos\mm\verifier.c for further details on DriverVerifier support in
* the memory manager.
*
* See sdk\inc\ntexapi.h for details on the DriverVerifier flags.
*
* Created: 19-Jan-1999 11:51:51
* Author: Gilman Wong [gilmanw]
*
* Copyright (c) 1999 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
#include "muclean.hxx"
#include "verifier.hxx"
extern BOOL G_fConsole; // gre\misc.cxx
//
// Amount of elapsed time before we begin random failures.
// Gives system time to stabilize.
//
// Taken from ntos\mm\verifier.c
//
LARGE_INTEGER GreBootTime;
const LARGE_INTEGER VerifierRequiredTimeSinceBoot = {(ULONG)(40 * 1000 * 1000 * 10), 1};
//
// Global verifier state.
//
VSTATE gvs = {
0, // fl
FALSE, // bSystemStable
0, // ulRandomSeed
0xf, // ulFailureMask
0, // ulDebugLevel
(HSEMAPHORE) NULL // hsemPoolTracker
};
//
// Put initialization functions in the INIT segment.
//
#pragma alloc_text(INIT, VerifierInitialization)
/******************************Public*Routine******************************\
* VerifierInitialization
*
* Initializes the DriverVerifier support in GRE. The loader will actually
* handle the fixup of the EngAllocMem, etc. during the loading of components
* listed as under the verifier.
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
#define VERIFIERFUNC(pfn) ((PDRIVER_VERIFIER_THUNK_ROUTINE)(pfn))
const DRIVER_VERIFIER_THUNK_PAIRS gaVerifierFunctionTable[] = {
{VERIFIERFUNC(EngAllocMem ), VERIFIERFUNC(VerifierEngAllocMem )},
{VERIFIERFUNC(EngFreeMem ), VERIFIERFUNC(VerifierEngFreeMem )},
{VERIFIERFUNC(EngAllocUserMem ), VERIFIERFUNC(VerifierEngAllocUserMem )},
{VERIFIERFUNC(EngFreeUserMem ), VERIFIERFUNC(VerifierEngFreeUserMem )},
{VERIFIERFUNC(EngCreateBitmap ), VERIFIERFUNC(VerifierEngCreateBitmap )},
{VERIFIERFUNC(EngCreateDeviceSurface), VERIFIERFUNC(VerifierEngCreateDeviceSurface)},
{VERIFIERFUNC(EngCreateDeviceBitmap ), VERIFIERFUNC(VerifierEngCreateDeviceBitmap )},
{VERIFIERFUNC(EngCreatePalette ), VERIFIERFUNC(VerifierEngCreatePalette )},
{VERIFIERFUNC(EngCreateClip ), VERIFIERFUNC(VerifierEngCreateClip )},
{VERIFIERFUNC(EngCreatePath ), VERIFIERFUNC(VerifierEngCreatePath )},
{VERIFIERFUNC(EngCreateWnd ), VERIFIERFUNC(VerifierEngCreateWnd )},
{VERIFIERFUNC(EngCreateDriverObj ), VERIFIERFUNC(VerifierEngCreateDriverObj )},
{VERIFIERFUNC(BRUSHOBJ_pvAllocRbrush), VERIFIERFUNC(VerifierBRUSHOBJ_pvAllocRbrush)},
{VERIFIERFUNC(CLIPOBJ_ppoGetPath ), VERIFIERFUNC(VerifierCLIPOBJ_ppoGetPath )}
};
BOOL
VerifierInitialization()
{
BOOL bRet = FALSE;
NTSTATUS Status;
ULONG Level;
#ifdef VERIFIER_STATISTICS
//
// Clear statistics.
//
RtlZeroMemory((VOID *) gvs.avs, sizeof(VSTATS) * VERIFIER_INDEX_LAST);
#endif
//
// Get the DriverVerifier flags. No point in going on if we can't
// get this.
//
Status = MmIsVerifierEnabled (&Level);
if ((NT_SUCCESS(Status) || (Status == STATUS_INFO_LENGTH_MISMATCH)) &&
(Level & DRIVER_VERIFIER_GRE_MASK))
{
//
// Some things should only be done once, during system initalization.
// So don't do them for Hydra sessions.
//
if (G_fConsole)
{
//
// Remember the boot time. We do not allow random failures for
// a period time right after boot to allow the system time to
// become quiescent.
//
KeQuerySystemTime(&GreBootTime);
//
// Give loader Verifier function substitution table.
//
Status = MmAddVerifierThunks ((VOID *) gaVerifierFunctionTable,
sizeof(gaVerifierFunctionTable));
if (NT_SUCCESS(Status))
{
VERIFIERWARNING(1, "VerifierInitialization: thunks accepted\n");
bRet = TRUE;
}
}
else
{
//
// On Hydra systems, allow failures during GRE initialization.
// So disable the check that allows the system time to stabilize.
//
gvs.bSystemStable = TRUE;
Level &= ~DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS;
bRet = TRUE;
}
}
else
{
WARNING("VerifierInitialization: failed to get info from ntoskrnl\n");
}
//
// Disable pool tracking always for graphic drivers. (NTBUG:421768)
//
Level &= ~DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS;
// //
// // Initialize pool tracking if needed.
// //
// if (Level & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)
// {
// //
// // Initialize doubly linked list used to track pool allocations.
// //
//
// InitializeListHead(&gvs.lePoolTrackerHead);
//
// //
// // Initialize the tracking list lock. Turn off pool allocations
// // if semaphore creation fails.
// //
//
// gvs.hsemPoolTracker = GreCreateSemaphore();
// if (!gvs.hsemPoolTracker)
// Level &= ~DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS;
// }
//
// Keep a local copy of the DriverVerifier flags.
//
// Note that the DriverVerifier flags can change on the fly without
// rebooting so this is a very transient copy.
//
// Wait until we know everthing is OK.
//
gvs.fl = (bRet) ? Level : 0;
return bRet;
}
/******************************Public*Routine******************************\
* VerifierRandomFailure
*
* Occasionally returns TRUE, indicating that Verifier should inject an
* allocation failure.
*
* See ntos\mm\verifier.c for further details.
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL FASTCALL
VerifierRandomFailure(ULONG ulEntry)
{
BOOL bRet = FALSE;
LARGE_INTEGER CurrentTime;
#ifdef VERIFIER_STATISTICS
ASSERTGDI(ulEntry < VERIFIER_INDEX_LAST,
"VerifierRandomFailure: bad index\n");
#else
DONTUSE(ulEntry);
#endif
//
// Check if random failures enabled.
//
if (gvs.fl & DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES)
{
//
// Don't fail any requests in the first 7 or 8 minutes as we want to
// give the system enough time to boot.
//
if (gvs.bSystemStable == FALSE)
{
KeQuerySystemTime(&CurrentTime);
if (CurrentTime.QuadPart > (GreBootTime.QuadPart + VerifierRequiredTimeSinceBoot.QuadPart))
{
//
// Enough time has elapsed to begin failures.
//
VERIFIERWARNING(1, "VerifierRandomFailure: injected failures enabled\n");
gvs.bSystemStable = TRUE;
gvs.ulRandomSeed = CurrentTime.LowPart;
#ifdef VERIFIER_STATISTICS
//
// Reset statistics.
//
RtlZeroMemory((VOID *) gvs.avs, sizeof(VSTATS) * VERIFIER_INDEX_LAST);
#endif
}
}
#ifdef VERIFIER_STATISTICS
//
// Record number of attempts.
//
InterlockedIncrement((LONG *) &gvs.avs[ulEntry].ulAttempts);
#endif
//
// Once system is stable, randomly enable failure.
//
if (gvs.bSystemStable)
{
if ((RtlRandom(&gvs.ulRandomSeed) & gvs.ulFailureMask) == 0)
{
bRet = TRUE;
#ifdef VERIFIER_STATISTICS
//
// Record number of injected failures.
//
InterlockedIncrement((LONG *) &gvs.avs[ulEntry].ulFailures);
#endif
}
}
}
return bRet;
}
/******************************Public*Routine******************************\
* VerifierEngAllocMem
*
* VerifierEngAllocMem can put allocations under special pool, track
* allocations, and inject random allocation failures.
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
PVOID APIENTRY
VerifierEngAllocMem(
ULONG fl,
ULONG cj,
ULONG tag
)
{
PVOID pvRet;
POOL_TYPE poolType;
EX_POOL_PRIORITY poolPriority;
ULONG cjOrig = cj;
//
// Inject random failures.
//
if (VerifierRandomFailure(VERIFIER_INDEX_EngAllocMem))
{
VERIFIERWARNING(1, "VerifierEngAllocMem: inject failure\n");
return NULL;
}
//
// Check if special pool is enabled.
//
if (gvs.fl & DRIVER_VERIFIER_SPECIAL_POOLING)
poolPriority = (EX_POOL_PRIORITY) (HighPoolPrioritySpecialPoolOverrun | POOL_SPECIAL_POOL_BIT);
else
poolPriority = HighPoolPrioritySpecialPoolOverrun;
//
// Don't trust the driver to only ask for non-zero length buffers.
//
if (cj == 0)
return NULL;
//
// Adjust size to include VERIFIERTRACKHDR.
//
if (gvs.fl & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)
{
if (cj <= (MAXULONG - sizeof(VERIFIERTRACKHDR)))
cj += ((ULONG) sizeof(VERIFIERTRACKHDR));
else
return NULL;
}
//
// Adjust size to include ENGTRACKHDR header.
//
// Sundown note: sizeof(ENGTRACKHDR) will fit in 32-bit, so ULONG cast OK
//
if (cj <= (MAXULONG - sizeof(ENGTRACKHDR)))
cj += ((ULONG) sizeof(ENGTRACKHDR));
else
return NULL;
if (cj >= (PAGE_SIZE * 10000))
{
WARNING("EngAllocMem: temp buffer >= 10000 pages");
return NULL;
}
//
// Need to call GdiAllocPoolNonPagedWithPriority or GdiAllocPoolWithPriority, which allows for
// special pool allocations.
//
if (fl & FL_NONPAGED_MEMORY) {
pvRet = GdiAllocPoolNonPagedWithPriority(cj, tag, poolPriority);
} else {
pvRet = GdiAllocPoolWithPriority(cj, tag, poolPriority);
}
if (pvRet)
{
if (fl & FL_ZERO_MEMORY)
{
RtlZeroMemory(pvRet, cj);
}
//
// Hydra pool tracking.
//
//
// Add allocation to the tracking list.
//
ENGTRACKHDR *pethNew = (ENGTRACKHDR *) pvRet;
MultiUserGreTrackAddEngResource(pethNew, ENGTRACK_VERIFIERALLOCMEM);
//
// Adjust return pointer to hide the LIST_ENTRY header.
//
pvRet = (PVOID) (pethNew + 1);
//
// Verifier pool tracking. Separate from Hydra
// pool tracking which handles session cleanup.
//
if (gvs.fl & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)
{
//
// Add to the tracking list.
//
VERIFIERTRACKHDR *pvthNew = (VERIFIERTRACKHDR *) pvRet;
pvthNew->ulSize = cjOrig;
pvthNew->ulTag = tag;
GreAcquireSemaphore(gvs.hsemPoolTracker);
InsertTailList(&gvs.lePoolTrackerHead, ((PLIST_ENTRY) pvthNew));
GreReleaseSemaphore(gvs.hsemPoolTracker);
//
// Adjust return pointer to hide the header.
//
pvRet = (PVOID) (pvthNew + 1);
}
}
return pvRet;
}
/******************************Public*Routine******************************\
* VerifierEngFreeMem
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID APIENTRY
VerifierEngFreeMem(
PVOID pv
)
{
if (pv)
{
//
// Verifier pool tracking.
//
if (gvs.fl & DRIVER_VERIFIER_TRACK_POOL_ALLOCATIONS)
{
//
// Remove victim from tracking list.
//
VERIFIERTRACKHDR *pvthVictim = ((VERIFIERTRACKHDR *) pv) - 1;
GreAcquireSemaphore(gvs.hsemPoolTracker);
RemoveEntryList(((PLIST_ENTRY) pvthVictim));
GreReleaseSemaphore(gvs.hsemPoolTracker);
//
// Adjust pointer to the header. This is base of allocation
// if not hydra.
//
pv = (PVOID) pvthVictim;
}
//
// Hydra pool tracking.
//
//
// Remove victim from tracking list.
//
ENGTRACKHDR *pethVictim = ((ENGTRACKHDR *) pv) - 1;
MultiUserGreTrackRemoveEngResource(pethVictim);
//
// Adjust pointer to the header. This is base of allocation if
// hydra.
//
pv = (PVOID) pethVictim;
GdiFreePool(pv);
}
return;
}
/******************************Public*Routine******************************\
* VerififierEngAllocUserMem
*
* This routine allocates a piece of memory for USER mode and locks it
* down. A driver must be very careful with this memory as it is only
* valid for this process.
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
PVOID APIENTRY
VerifierEngAllocUserMem(
SIZE_T cj,
ULONG tag
)
{
//
// Inject random failures.
//
if (VerifierRandomFailure(VERIFIER_INDEX_EngAllocUserMem))
{
VERIFIERWARNING(1, "VerifierEngAllocUserMem: inject failure\n");
return NULL;
}
else
return EngAllocUserMem(cj, tag);
}
/******************************Public*Routine******************************\
* VerifierEngFreeUserMem
*
* History:
* 19-Jan-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID APIENTRY
VerifierEngFreeUserMem(
PVOID pv
)
{
//
// Right now, there is no difference between this and EngFreeUserMem.
// However, we may soon add some tracking info, so here is a stub.
//
EngFreeUserMem(pv);
return;
}
/******************************Public*Routine******************************\
* VerifierEngCreateBitmap
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HBITMAP APIENTRY VerifierEngCreateBitmap(
SIZEL sizl,
LONG lWidth,
ULONG iFormat,
FLONG fl,
PVOID pvBits
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateBitmap))
{
VERIFIERWARNING(1, "VerifierEngCreateBitmap: inject failure\n");
return NULL;
}
else
return EngCreateBitmap(sizl, lWidth, iFormat, fl, pvBits);
}
/******************************Public*Routine******************************\
* VerifierEngCreateDeviceSurface
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HSURF APIENTRY VerifierEngCreateDeviceSurface(
DHSURF dhsurf,
SIZEL sizl,
ULONG iFormatCompat
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateDeviceSurface))
{
VERIFIERWARNING(1, "VerifierEngCreateDeviceSurface: inject failure\n");
return NULL;
}
else
return EngCreateDeviceSurface(dhsurf, sizl, iFormatCompat);
}
/******************************Public*Routine******************************\
* VerifierEngCreateDeviceBitmap
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HBITMAP APIENTRY VerifierEngCreateDeviceBitmap(
DHSURF dhsurf,
SIZEL sizl,
ULONG iFormatCompat
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateDeviceBitmap))
{
VERIFIERWARNING(1, "VerifierEngCreateDeviceBitmap: inject failure\n");
return NULL;
}
else
return EngCreateDeviceBitmap(dhsurf, sizl, iFormatCompat);
}
/******************************Public*Routine******************************\
* VerifierEngCreatePalette
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HPALETTE APIENTRY VerifierEngCreatePalette(
ULONG iMode,
ULONG cColors,
ULONG *pulColors,
FLONG flRed,
FLONG flGreen,
FLONG flBlue
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreatePalette))
{
VERIFIERWARNING(1, "VerifierEngCreatePalette: inject failure\n");
return NULL;
}
else
return EngCreatePalette(iMode, cColors, pulColors,
flRed, flGreen, flBlue);
}
/******************************Public*Routine******************************\
* VerifierEngCreateClip
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
CLIPOBJ * APIENTRY VerifierEngCreateClip()
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateClip))
{
VERIFIERWARNING(1, "VerifierEngCreateClip: inject failure\n");
return NULL;
}
else
return EngCreateClip();
}
/******************************Public*Routine******************************\
* VerifierEngCreatePath
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
PATHOBJ * APIENTRY VerifierEngCreatePath()
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreatePath))
{
VERIFIERWARNING(1, "VerifierEngCreatePath: inject failure\n");
return NULL;
}
else
return EngCreatePath();
}
/******************************Public*Routine******************************\
* VerifierEngCreateWnd
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
WNDOBJ * APIENTRY VerifierEngCreateWnd(
SURFOBJ *pso,
HWND hwnd,
WNDOBJCHANGEPROC pfn,
FLONG fl,
int iPixelFormat
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateWnd))
{
VERIFIERWARNING(1, "VerifierEngCreateWnd: inject failure\n");
return NULL;
}
else
return EngCreateWnd(pso, hwnd, pfn, fl, iPixelFormat);
}
/******************************Public*Routine******************************\
* VerifierEngCreateDriverObj
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HDRVOBJ APIENTRY VerifierEngCreateDriverObj(
PVOID pvObj,
FREEOBJPROC pFreeObjProc,
HDEV hdev
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_EngCreateDriverObj))
{
VERIFIERWARNING(1, "VerifierEngCreateDriverObj: inject failure\n");
return NULL;
}
else
return EngCreateDriverObj(pvObj, pFreeObjProc, hdev);
}
/******************************Public*Routine******************************\
* VerifierBRUSHOBJ_pvAllocRbrush
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
PVOID APIENTRY VerifierBRUSHOBJ_pvAllocRbrush(
BRUSHOBJ *pbo,
ULONG cj
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_BRUSHOBJ_pvAllocRbrush))
{
VERIFIERWARNING(1, "VerifierBRUSHOBJ_pvAllocRbrush: inject failure\n");
return NULL;
}
else
return BRUSHOBJ_pvAllocRbrush(pbo, cj);
}
/******************************Public*Routine******************************\
* VerifierCLIPOBJ_ppoGetPath
*
* Only supports random failure.
*
* History:
* 02-Feb-1999 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
PATHOBJ* APIENTRY VerifierCLIPOBJ_ppoGetPath(
CLIPOBJ* pco
)
{
if (VerifierRandomFailure(VERIFIER_INDEX_CLIPOBJ_ppoGetPath))
{
VERIFIERWARNING(1, "VerifierCLIPOBJ_ppoGetPath: inject failure\n");
return NULL;
}
else
return CLIPOBJ_ppoGetPath(pco);
}