|
|
/**************************** Module Header ********************************\
* Module Name: pool.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Pool reallocation routines * * History: * 03-04-95 JimA Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
DWORD gdwPoolFlags; DWORD gSessionPoolMask;
#ifdef POOL_INSTR
/*
* Globals used by RecordStackTrace */
PVOID gRecordedStackTrace[RECORD_STACK_TRACE_SIZE]; PEPROCESS gpepRecorded; PETHREAD gpetRecorded;
DWORD gdwAllocFailIndex; // the index of the allocation that's
// going to fail
DWORD gdwAllocsToFail = 1; // how many allocs to fail
DWORD gdwFreeRecords;
/*
* Targeted tag failures */ LPDWORD gparrTagsToFail; SIZE_T gdwTagsToFailCount;
/*
* Support to keep records of failed pool allocations */ DWORD gdwFailRecords; DWORD gdwFailRecordCrtIndex; DWORD gdwFailRecordTotalFailures;
PPOOLRECORD gparrFailRecord;
/*
* Support to keep records of pool free */ DWORD gdwFreeRecords; DWORD gdwFreeRecordCrtIndex; DWORD gdwFreeRecordTotalFrees;
PPOOLRECORD gparrFreeRecord;
FAST_MUTEX* gpAllocFastMutex; // mutex to syncronize pool allocations
Win32AllocStats gAllocList;
CONST char gszTailAlloc[] = "Win32kAlloc";
#define USESESSION(dwFlags) (((dwFlags & DAP_NONSESSION) != 0) ? 0 : gSessionPoolMask)
#endif
/***************************************************************************\
* Win32QueryPoolSize * * Returns the size of the given pool block. * * 08-17-2001 JasonSch Created. \***************************************************************************/ SIZE_T Win32QueryPoolSize( PVOID p) { /*
* If POOL_HEAVY_ALLOCS is not defined then the pointer is what * we allocated. */ if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { BOOLEAN notUsed; return ExQueryPoolBlockSize(p, ¬Used); } else { PWin32PoolHead ph;
ph = (PWin32PoolHead)((DWORD*)p - (sizeof(Win32PoolHead) / sizeof(DWORD))); return ph->size; } }
PVOID Win32AllocPoolWithTagZInit(SIZE_T uBytes, ULONG uTag) { PVOID pv;
pv = Win32AllocPool(uBytes, uTag); if (pv) { RtlZeroMemory(pv, uBytes); }
return pv; }
PVOID Win32AllocPoolWithTagZInitWithPriority(SIZE_T uBytes, ULONG uTag, EX_POOL_PRIORITY priority) { PVOID pv;
pv = Win32AllocPoolWithPriority(uBytes, uTag, priority); if (pv) { RtlZeroMemory(pv, uBytes); }
return pv; }
PVOID Win32AllocPoolWithQuotaTagZInit(SIZE_T uBytes, ULONG uTag) { PVOID pv;
pv = Win32AllocPoolWithQuota(uBytes, uTag); if (pv) { RtlZeroMemory(pv, uBytes); }
return pv; }
PVOID UserReAllocPoolWithTag( PVOID pSrc, SIZE_T uBytesSrc, SIZE_T uBytes, ULONG iTag) { PVOID pDest;
pDest = UserAllocPool(uBytes, iTag); if (pDest != NULL) {
/*
* If the block is shrinking, don't copy too many bytes. */ if (uBytesSrc > uBytes) { uBytesSrc = uBytes; }
RtlCopyMemory(pDest, pSrc, uBytesSrc);
UserFreePool(pSrc); }
return pDest; }
PVOID UserReAllocPoolWithQuotaTag( PVOID pSrc, SIZE_T uBytesSrc, SIZE_T uBytes, ULONG iTag) { PVOID pDest;
pDest = UserAllocPoolWithQuota(uBytes, iTag); if (pDest != NULL) {
/*
* If the block is shrinking, don't copy too many bytes. */ if (uBytesSrc > uBytes) uBytesSrc = uBytes;
RtlCopyMemory(pDest, pSrc, uBytesSrc);
UserFreePool(pSrc); }
return pDest; }
/*
* Allocation routines for rtl functions */
PVOID UserRtlAllocMem( SIZE_T uBytes) { return UserAllocPool(uBytes, TAG_RTL); }
VOID UserRtlFreeMem( PVOID pMem) { UserFreePool(pMem); }
#ifdef POOL_INSTR
VOID RecordStackTrace( VOID) { RtlZeroMemory(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE, 0);
gpepRecorded = PsGetCurrentProcess(); gpetRecorded = PsGetCurrentThread(); }
/***************************************************************************\
* RecordFailAllocation * * Records failed allocations * * 3-22-99 CLupu Created. \***************************************************************************/ VOID RecordFailAllocation( ULONG tag, SIZE_T size) { UserAssert(gdwPoolFlags & POOL_KEEP_FAIL_RECORD);
gparrFailRecord[gdwFailRecordCrtIndex].ExtraData = LongToPtr( tag ); gparrFailRecord[gdwFailRecordCrtIndex].size = size;
gdwFailRecordTotalFailures++;
RtlZeroMemory(gparrFailRecord[gdwFailRecordCrtIndex].trace, RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(gparrFailRecord[gdwFailRecordCrtIndex].trace, RECORD_STACK_TRACE_SIZE, 0);
gdwFailRecordCrtIndex++;
if (gdwFailRecordCrtIndex >= gdwFailRecords) { gdwFailRecordCrtIndex = 0; } }
/***************************************************************************\
* RecordFreePool * * Records free pool * * 3-22-99 CLupu Created. \***************************************************************************/ VOID RecordFreePool( PVOID p, SIZE_T size) { UserAssert(gdwPoolFlags & POOL_KEEP_FREE_RECORD);
gparrFreeRecord[gdwFreeRecordCrtIndex].ExtraData = p; gparrFreeRecord[gdwFreeRecordCrtIndex].size = size;
gdwFreeRecordTotalFrees++;
RtlZeroMemory(gparrFreeRecord[gdwFreeRecordCrtIndex].trace, RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(gparrFreeRecord[gdwFreeRecordCrtIndex].trace, RECORD_STACK_TRACE_SIZE, 0);
gdwFreeRecordCrtIndex++;
if (gdwFreeRecordCrtIndex >= gdwFreeRecords) { gdwFreeRecordCrtIndex = 0; } }
/***************************************************************************\
* HeavyAllocPool * * This will make UserAllocPool to fail if we do not provide enough memory * for the specified tag. * * 12-02-96 CLupu Created. \***************************************************************************/ PVOID HeavyAllocPool( SIZE_T uBytes, ULONG tag, DWORD dwFlags, EX_POOL_PRIORITY priority) { PDWORD p; PWin32PoolHead ph; POOL_TYPE poolType;
if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { if (dwFlags & DAP_USEQUOTA) { poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE : gSessionPoolMask | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE);
p = ExAllocatePoolWithQuotaTag(poolType, uBytes, tag); } else { poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool : gSessionPoolMask | PagedPool);
if (dwFlags & DAP_PRIORITY) { p = ExAllocatePoolWithTagPriority(poolType, uBytes, tag, priority); } else { p = ExAllocatePoolWithTag(poolType, uBytes, tag); }
}
if (p != NULL && (dwFlags & DAP_ZEROINIT)) { RtlZeroMemory(p, uBytes); }
return p; }
/*
* Check for overflow. */ if (uBytes >= MAXULONG - sizeof(Win32PoolHead) - sizeof(gszTailAlloc)) { if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { RecordFailAllocation(tag, 0); }
return NULL; }
/*
* Acquire the mutex when we play with the list of allocations. */ KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(gpAllocFastMutex);
#ifdef POOL_INSTR_API
/*
* Fail the allocation if the flag is set. Don't fail allocations that * will certainly get us to bugcheck in DBG (i.e. GLOBALTHREADLOCK). */ if (gdwPoolFlags & POOL_FAIL_ALLOCS #if DBG
&& (tag != TAG_GLOBALTHREADLOCK) #endif
) {
SIZE_T dwInd;
for (dwInd = 0; dwInd < gdwTagsToFailCount; dwInd++) { if (tag == gparrTagsToFail[dwInd]) { break; } }
if (dwInd < gdwTagsToFailCount) { if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { RecordFailAllocation(tag, uBytes); }
RIPMSG0(RIP_WARNING, "Pool allocation failed because of global restriction"); p = NULL; goto exit; } } #endif
#if DBG
if ((gdwPoolFlags & POOL_FAIL_BY_INDEX) && (tag != TAG_GLOBALTHREADLOCK)) { /*
* Count the calls to HeavyAllocPool. */ gdwAllocCrt++;
if (gdwAllocCrt >= gdwAllocFailIndex && gdwAllocCrt < gdwAllocFailIndex + gdwAllocsToFail) {
RecordStackTrace();
KdPrint(("\n--------------------------------------------------\n")); KdPrint(( "\nPool allocation %d failed because of registry settings", gdwAllocCrt)); KdPrint(("\n--------------------------------------------------\n\n"));
if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { RecordFailAllocation(tag, uBytes); } p = NULL; goto exit; } } #endif
/*
* Reserve space for the header */ uBytes += sizeof(Win32PoolHead);
if (gdwPoolFlags & POOL_TAIL_CHECK) { uBytes += sizeof(gszTailAlloc); }
if (dwFlags & DAP_USEQUOTA) { poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE : gSessionPoolMask | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE);
p = ExAllocatePoolWithQuotaTag(poolType, uBytes, tag); } else { poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags)| NonPagedPool : gSessionPoolMask | PagedPool);
if (dwFlags & DAP_PRIORITY) { p = ExAllocatePoolWithTagPriority(poolType, uBytes, tag, priority); } else { p = ExAllocatePoolWithTag(poolType, uBytes, tag); } }
/*
* Return if ExAllocate... failed. */ if (p == NULL) { if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) { uBytes -= sizeof(Win32PoolHead);
if (gdwPoolFlags & POOL_TAIL_CHECK) { uBytes -= sizeof(gszTailAlloc); }
RecordFailAllocation(tag, uBytes); }
goto exit; }
if (gdwPoolFlags & POOL_TAIL_CHECK) { uBytes -= sizeof(gszTailAlloc);
RtlCopyMemory(((BYTE*)p) + uBytes, gszTailAlloc, sizeof(gszTailAlloc)); }
uBytes -= sizeof(Win32PoolHead);
/*
* Get the pointer to the header. */ ph = (PWin32PoolHead)p;
p += (sizeof(Win32PoolHead) / sizeof(DWORD));
/*
* Update the global allocations info. */ gAllocList.dwCrtMem += uBytes;
if (gAllocList.dwMaxMem < gAllocList.dwCrtMem) { gAllocList.dwMaxMem = gAllocList.dwCrtMem; }
(gAllocList.dwCrtAlloc)++;
if (gAllocList.dwMaxAlloc < gAllocList.dwCrtAlloc) { gAllocList.dwMaxAlloc = gAllocList.dwCrtAlloc; }
/*
* Grab the stack traces if the flags say so */ if (gdwPoolFlags & POOL_CAPTURE_STACK) { ph->pTrace = ExAllocatePoolWithTag(gSessionPoolMask | PagedPool, POOL_ALLOC_TRACE_SIZE * sizeof(PVOID), TAG_STACK);
if (ph->pTrace != NULL) { RtlZeroMemory(ph->pTrace, POOL_ALLOC_TRACE_SIZE * sizeof(PVOID)); RtlWalkFrameChain(ph->pTrace, POOL_ALLOC_TRACE_SIZE, 0); } } else { ph->pTrace = NULL; }
/*
* Save the info in the header and return the pointer after the header. */ ph->size = uBytes;
/*
* now, link it into the list for this tag (if any) */ ph->pPrev = NULL; ph->pNext = gAllocList.pHead;
if (gAllocList.pHead != NULL) { gAllocList.pHead->pPrev = ph; }
gAllocList.pHead = ph;
if (dwFlags & DAP_ZEROINIT) { RtlZeroMemory(p, uBytes); }
exit: /*
* Release the mutex */ ExReleaseFastMutexUnsafe(gpAllocFastMutex); KeLeaveCriticalRegion();
return p; }
/***************************************************************************\
* HeavyFreePool * * 12-02-96 CLupu Created. \***************************************************************************/ VOID HeavyFreePool( PVOID p) { SIZE_T uBytes; PWin32PoolHead ph;
/*
* If POOL_HEAVY_ALLOCS is not defined * then the pointer is what we allocated */ if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { ExFreePool(p); return; }
/*
* Acquire the mutex when we play with the list of allocations */ KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(gpAllocFastMutex);
ph = (PWin32PoolHead)((DWORD*)p - (sizeof(Win32PoolHead) / sizeof(DWORD)));
uBytes = ph->size;
/*
* Check the tail */ if (gdwPoolFlags & POOL_TAIL_CHECK) { if (!RtlEqualMemory((BYTE*)p + uBytes, gszTailAlloc, sizeof(gszTailAlloc))) { RIPMSG1(RIP_ERROR, "POOL CORRUPTION for %#p", p); } }
gAllocList.dwCrtMem -= uBytes;
UserAssert(gAllocList.dwCrtAlloc > 0);
(gAllocList.dwCrtAlloc)--;
/*
* now, remove it from the linked list */ if (ph->pPrev == NULL) { if (ph->pNext == NULL) {
UserAssert(gAllocList.dwCrtAlloc == 0);
gAllocList.pHead = NULL; } else { ph->pNext->pPrev = NULL; gAllocList.pHead = ph->pNext; } } else { ph->pPrev->pNext = ph->pNext; if (ph->pNext != NULL) { ph->pNext->pPrev = ph->pPrev; } }
/*
* Free the stack traces */ if (ph->pTrace != NULL) { ExFreePool(ph->pTrace); }
if (gdwPoolFlags & POOL_KEEP_FREE_RECORD) { RecordFreePool(ph, ph->size); }
ExFreePool(ph);
/*
* Release the mutex */ ExReleaseFastMutexUnsafe(gpAllocFastMutex); KeLeaveCriticalRegion(); }
/***************************************************************************\
* CleanupPoolAllocations * * 12-02-96 CLupu Created. \***************************************************************************/ VOID CleanupPoolAllocations( VOID) { PWin32PoolHead pHead; PWin32PoolHead pNext;
if (gAllocList.dwCrtAlloc != 0) { if (gdwPoolFlags & POOL_BREAK_FOR_LEAKS) { FRE_RIPMSG0(RIP_ERROR, "There is still pool memory not freed in win32k.sys.\n" "Use !userkdx.dpa -vs to dump it"); }
pHead = gAllocList.pHead; while (pHead != NULL) { pNext = pHead->pNext;
UserFreePool(pHead + 1);
pHead = pNext; } } }
/***************************************************************************\
* CleanUpPoolLimitations * \***************************************************************************/ VOID CleanUpPoolLimitations( VOID) { if (gpAllocFastMutex != NULL) { ExFreePool(gpAllocFastMutex); gpAllocFastMutex = NULL; }
if (gparrFailRecord != NULL) { ExFreePool(gparrFailRecord); gparrFailRecord = NULL; }
if (gparrFreeRecord != NULL) { ExFreePool(gparrFreeRecord); gparrFreeRecord = NULL; }
if (gparrTagsToFail != NULL) { ExFreePool(gparrTagsToFail); gparrTagsToFail = NULL; } }
/***************************************************************************\
* InitPoolLimitations * * 12-02-96 CLupu Created. \***************************************************************************/ NTSTATUS InitPoolLimitations( VOID) { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE hkey; NTSTATUS Status; WCHAR achKeyValue[512]; DWORD dwData; ULONG ucb;
/*
* Initialize a critical section structure that will be used to protect * all the HeavyAllocPool and HeavyFreePool calls. */ gpAllocFastMutex = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_DEBUG); if (gpAllocFastMutex == NULL) { RIPMSG0(RIP_WARNING, "InitPoolLimitations failed to allocate mutex"); return STATUS_NO_MEMORY; }
ExInitializeFastMutex(gpAllocFastMutex);
/*
* Allocate from session pool only for Full TS, that is Terminal Server * in app server mode. For normal Server (Remote Administration) or * workstation don't limit to session pool. */ if ((SharedUserData->SuiteMask & VER_SUITE_TERMINAL) && !(SharedUserData->SuiteMask & VER_SUITE_SINGLEUSERTS)) { gSessionPoolMask = SESSION_POOL_MASK;
if (gbRemoteSession) { gdwPoolFlags |= POOL_HEAVY_ALLOCS; } } else { gSessionPoolMask = 0; }
#if DBG
gdwPoolFlags |= (POOL_HEAVY_ALLOCS | POOL_CAPTURE_STACK | POOL_BREAK_FOR_LEAKS); #endif
/*
* Open the key containing the limits. */ RtlInitUnicodeString( &UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SubSystems\\Pool");
InitializeObjectAttributes( &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&hkey, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) {
#if DBG
/*
* More default settings if the Pool key doesn't exist */ if (gbRemoteSession) {
gparrFailRecord = ExAllocatePoolWithTag(PagedPool, 32 * sizeof(POOLRECORD), TAG_DEBUG);
if (gparrFailRecord != NULL) { gdwFailRecords = 32; gdwPoolFlags |= POOL_KEEP_FAIL_RECORD; }
gparrFreeRecord = ExAllocatePoolWithTag(PagedPool, 32 * sizeof(POOLRECORD), TAG_DEBUG);
if (gparrFreeRecord != NULL) { gdwFreeRecords = 32; gdwPoolFlags |= POOL_KEEP_FREE_RECORD; } } #endif
return STATUS_SUCCESS; }
if (gbRemoteSession) { /*
* Break in the debugger for memory leaks? */ RtlInitUnicodeString(&UnicodeString, L"BreakForPoolLeaks");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
if (dwData != 0) { gdwPoolFlags |= POOL_BREAK_FOR_LEAKS; } else { gdwPoolFlags &= ~POOL_BREAK_FOR_LEAKS; } }
/*
* Heavy allocs/frees for remote sessions ? */ RtlInitUnicodeString(&UnicodeString, L"HeavyRemoteSession");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
if (dwData == 0) { gdwPoolFlags &= ~POOL_HEAVY_ALLOCS; } } } else {
/*
* Heavy allocs/frees for main session ? */ RtlInitUnicodeString(&UnicodeString, L"HeavyConsoleSession");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
if (dwData != 0) { gdwPoolFlags |= POOL_HEAVY_ALLOCS; } } }
if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { ZwClose(hkey); return STATUS_SUCCESS; }
/*
* Check for stack traces */ RtlInitUnicodeString(&UnicodeString, L"StackTraces");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
if (dwData == 0) { gdwPoolFlags &= ~POOL_CAPTURE_STACK; } else { gdwPoolFlags |= POOL_CAPTURE_STACK; } }
/*
* Use tail checks ? */ RtlInitUnicodeString(&UnicodeString, L"UseTailString");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
if (dwData != 0) { gdwPoolFlags |= POOL_TAIL_CHECK; } }
/*
* Keep a record of frees ? By default keep the last 32. */ #if DBG
gdwFreeRecords = 32; #endif
RtlInitUnicodeString(&UnicodeString, L"KeepFreeRecords");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
gdwFreeRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); }
if (gdwFreeRecords != 0) {
gparrFreeRecord = ExAllocatePoolWithTag(PagedPool, gdwFreeRecords * sizeof(POOLRECORD), TAG_DEBUG);
if (gparrFreeRecord != NULL) { gdwPoolFlags |= POOL_KEEP_FREE_RECORD; } }
/*
* Keep a record of failed allocations ? By default keep the last 32. */ #if DBG
gdwFailRecords = 32; #endif
RtlInitUnicodeString(&UnicodeString, L"KeepFailRecords");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
gdwFailRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); }
if (gdwFailRecords != 0) {
gparrFailRecord = ExAllocatePoolWithTag(PagedPool, gdwFailRecords * sizeof(POOLRECORD), TAG_DEBUG);
if (gparrFailRecord != NULL) { gdwPoolFlags |= POOL_KEEP_FAIL_RECORD; } }
#if DBG
/*
* Open the key containing the allocation that should fail. */ RtlInitUnicodeString(&UnicodeString, L"AllocationIndex");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
gdwAllocFailIndex = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); }
RtlInitUnicodeString(&UnicodeString, L"AllocationsToFail");
Status = ZwQueryValueKey( hkey, &UnicodeString, KeyValuePartialInformation, achKeyValue, sizeof(achKeyValue), &ucb);
if (NT_SUCCESS(Status) && ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
gdwAllocsToFail = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data); }
if (gdwAllocFailIndex != 0 && gdwAllocsToFail > 0) { gdwPoolFlags |= POOL_FAIL_BY_INDEX; } #endif
ZwClose(hkey);
return STATUS_SUCCESS; } #endif
#ifdef POOL_INSTR_API
BOOL _Win32PoolAllocationStats( LPDWORD parrTags, SIZE_T tagsCount, SIZE_T* lpdwMaxMem, SIZE_T* lpdwCrtMem, LPDWORD lpdwMaxAlloc, LPDWORD lpdwCrtAlloc) { BOOL bRet = FALSE;
/*
* Do nothing if heavy allocs/frees are disabled. */ if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) { return FALSE; }
*lpdwMaxMem = gAllocList.dwMaxMem; *lpdwCrtMem = gAllocList.dwCrtMem; *lpdwMaxAlloc = gAllocList.dwMaxAlloc; *lpdwCrtAlloc = gAllocList.dwCrtAlloc;
/*
* Acquire the mutex when we play with the list of allocations. */ KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(gpAllocFastMutex);
if (gparrTagsToFail != NULL) { ExFreePool(gparrTagsToFail); gparrTagsToFail = NULL; gdwTagsToFailCount = 0; }
if (tagsCount != 0) { gdwPoolFlags |= POOL_FAIL_ALLOCS;
if (tagsCount > MAX_TAGS_TO_FAIL) { gdwTagsToFailCount = 0xFFFFFFFF; RIPMSG0(RIP_WARNING, "All pool allocations in WIN32K.SYS will fail."); bRet = TRUE; goto exit; } } else { gdwPoolFlags &= ~POOL_FAIL_ALLOCS;
RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal."); bRet = TRUE; goto exit; }
gparrTagsToFail = ExAllocatePoolWithTag(PagedPool, sizeof(DWORD) * tagsCount, TAG_DEBUG);
if (gparrTagsToFail == NULL) { gdwPoolFlags &= ~POOL_FAIL_ALLOCS; RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal !"); goto exit; }
try { ProbeForRead(parrTags, sizeof(DWORD) * tagsCount, DATAALIGN); RtlCopyMemory(gparrTagsToFail, parrTags, sizeof(DWORD) * tagsCount); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { if (gparrTagsToFail != NULL) { ExFreePool(gparrTagsToFail); gparrTagsToFail = NULL;
gdwPoolFlags &= ~POOL_FAIL_ALLOCS; RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal."); goto exit; } } gdwTagsToFailCount = tagsCount;
RIPMSG0(RIP_WARNING, "Specific pool allocations in WIN32K.SYS will fail.");
exit: /*
* Release the mutex */ ExReleaseFastMutexUnsafe(gpAllocFastMutex); KeLeaveCriticalRegion();
return bRet; }
#endif
#ifdef TRACE_MAP_VIEWS
FAST_MUTEX* gpSectionFastMutex; PWin32Section gpSections;
#define EnterSectionCrit() \
KeEnterCriticalRegion(); \ ExAcquireFastMutexUnsafe(gpSectionFastMutex);
#define LeaveSectionCrit() \
ExReleaseFastMutexUnsafe(gpSectionFastMutex); \ KeLeaveCriticalRegion();
/***************************************************************************\
* CleanUpSections * \***************************************************************************/ VOID CleanUpSections( VOID) { if (gpSectionFastMutex) { ExFreePool(gpSectionFastMutex); gpSectionFastMutex = NULL; } }
NTSTATUS InitSectionTrace( VOID) { gpSectionFastMutex = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_DEBUG);
if (gpSectionFastMutex == NULL) { RIPMSG0(RIP_WARNING, "InitSectionTrace failed to allocate mutex"); return STATUS_NO_MEMORY; }
ExInitializeFastMutex(gpSectionFastMutex);
return STATUS_SUCCESS; }
NTSTATUS _Win32CreateSection( PVOID* pSectionObject, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER pInputMaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle, PFILE_OBJECT FileObject, DWORD SectionTag) { PWin32Section pSection; NTSTATUS Status;
Status = MmCreateSection( pSectionObject, DesiredAccess, ObjectAttributes, pInputMaximumSize, SectionPageProtection, AllocationAttributes, FileHandle, FileObject);
if (NT_SUCCESS(Status)) { ObDeleteCapturedInsertInfo(*pSectionObject); } else { RIPMSG1(RIP_WARNING, "MmCreateSection failed with Status 0x%x.", Status); *pSectionObject = NULL; return Status; }
pSection = UserAllocPoolZInit(sizeof(Win32Section), TAG_SECTION);
if (pSection == NULL) { ObDereferenceObject(*pSectionObject); RIPMSG0(RIP_WARNING, "Failed to allocate memory for section."); *pSectionObject = NULL; return STATUS_UNSUCCESSFUL; }
EnterSectionCrit();
pSection->pNext = gpSections; if (gpSections != NULL) { UserAssert(gpSections->pPrev == NULL); gpSections->pPrev = pSection; }
pSection->SectionObject = *pSectionObject; pSection->SectionSize = *pInputMaximumSize; pSection->SectionTag = SectionTag;
gpSections = pSection;
#ifdef MAP_VIEW_STACK_TRACE
RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
#endif
LeaveSectionCrit();
return STATUS_SUCCESS; }
NTSTATUS _ZwWin32CreateSection( PVOID* pSectionObject, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER pInputMaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle, PFILE_OBJECT FileObject, DWORD SectionTag) { PWin32Section pSection; NTSTATUS Status; HANDLE SectionHandle;
UNREFERENCED_PARAMETER(FileObject);
Status = ZwCreateSection( &SectionHandle, DesiredAccess, ObjectAttributes, pInputMaximumSize, SectionPageProtection, AllocationAttributes, FileHandle);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "ZwCreateSection failed with Statu %x", Status); *pSectionObject = NULL; return Status; }
Status = ObReferenceObjectByHandle( SectionHandle, DesiredAccess, *(POBJECT_TYPE *)MmSectionObjectType, KernelMode, pSectionObject, NULL);
ZwClose(SectionHandle);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "ObReferenceObjectByHandle failed with Status 0x%x", Status); *pSectionObject = NULL; return Status; }
pSection = UserAllocPoolZInit(sizeof(Win32Section), TAG_SECTION); if (pSection == NULL) { ObDereferenceObject(*pSectionObject); RIPMSG0(RIP_WARNING, "Failed to allocate memory for section"); *pSectionObject = NULL; return STATUS_UNSUCCESSFUL; }
EnterSectionCrit();
pSection->pNext = gpSections; if (gpSections != NULL) { UserAssert(gpSections->pPrev == NULL); gpSections->pPrev = pSection; }
pSection->SectionObject = *pSectionObject; pSection->SectionSize = *pInputMaximumSize; pSection->SectionTag = SectionTag;
gpSections = pSection;
#ifdef MAP_VIEW_STACK_TRACE
RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
#endif
LeaveSectionCrit();
return STATUS_SUCCESS; }
VOID _Win32DestroySection( PVOID Section) { PWin32Section ps;
EnterSectionCrit();
ps = gpSections;
while (ps != NULL) { if (ps->SectionObject == Section) {
/*
* Make sure there is no view mapped for this section */ if (ps->pFirstView != NULL) { RIPMSG1(RIP_ERROR, "Section %#p still has views", ps); }
/*
* now, remove it from the linked list of this tag */ if (ps->pPrev == NULL) {
UserAssert(ps == gpSections);
gpSections = ps->pNext;
if (ps->pNext != NULL) { ps->pNext->pPrev = NULL; } } else { ps->pPrev->pNext = ps->pNext; if (ps->pNext != NULL) { ps->pNext->pPrev = ps->pPrev; } } ObDereferenceObject(Section); UserFreePool(ps); LeaveSectionCrit(); return; } ps = ps->pNext; }
RIPMSG1(RIP_ERROR, "Cannot find Section %#p", Section); LeaveSectionCrit(); }
NTSTATUS _Win32MapViewInSessionSpace( PVOID Section, PVOID* pMappedBase, PSIZE_T pViewSize) { NTSTATUS Status; PWin32Section ps; PWin32MapView pMapView;
/*
* First try to map the view */ Status = MmMapViewInSessionSpace(Section, pMappedBase, pViewSize);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "MmMapViewInSessionSpace failed with Status %x", Status); *pMappedBase = NULL; return Status; }
/*
* Now add a record for this view */ pMapView = UserAllocPoolZInit(sizeof(Win32MapView), TAG_SECTION);
if (pMapView == NULL) { RIPMSG0(RIP_WARNING, "_Win32MapViewInSessionSpace: Memory failure");
MmUnmapViewInSessionSpace(*pMappedBase); *pMappedBase = NULL; return STATUS_NO_MEMORY; }
pMapView->pViewBase = *pMappedBase; pMapView->ViewSize = *pViewSize;
EnterSectionCrit();
ps = gpSections;
while (ps != NULL) { if (ps->SectionObject == Section) {
pMapView->pSection = ps;
pMapView->pNext = ps->pFirstView;
if (ps->pFirstView != NULL) { ps->pFirstView->pPrev = pMapView; } ps->pFirstView = pMapView;
#ifdef MAP_VIEW_STACK_TRACE
RtlZeroMemory(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
RtlWalkFrameChain(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
#endif
LeaveSectionCrit(); return STATUS_SUCCESS; } ps = ps->pNext; }
RIPMSG1(RIP_ERROR, "_Win32MapViewInSessionSpace: Could not find section for %#p", Section);
LeaveSectionCrit();
return STATUS_UNSUCCESSFUL; }
NTSTATUS _Win32UnmapViewInSessionSpace( PVOID MappedBase) { PWin32Section ps; PWin32MapView pv; NTSTATUS Status;
EnterSectionCrit();
ps = gpSections;
while (ps != NULL) {
pv = ps->pFirstView;
while (pv != NULL) {
UserAssert(pv->pSection == ps);
if (pv->pViewBase == MappedBase) { /*
* now, remove it from the linked list */ if (pv->pPrev == NULL) {
UserAssert(pv == ps->pFirstView);
ps->pFirstView = pv->pNext;
if (pv->pNext != NULL) { pv->pNext->pPrev = NULL; } } else { pv->pPrev->pNext = pv->pNext; if (pv->pNext != NULL) { pv->pNext->pPrev = pv->pPrev; } }
UserFreePool(pv);
Status = MmUnmapViewInSessionSpace(MappedBase);
LeaveSectionCrit();
return Status; } pv = pv->pNext; } ps = ps->pNext; }
RIPMSG1(RIP_ERROR, "_Win32UnmapViewInSessionSpace: Could not find view for 0x%p", MappedBase);
LeaveSectionCrit();
return STATUS_UNSUCCESSFUL; } #endif
|