00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
#include "precomp.h"
00013
#pragma hdrstop
00014
00015 BOOL gdwPoolFlags;
00016
00017
#ifdef POOL_INSTR
00018
00019
00020
00021
00022
00023 PVOID gRecordedStackTrace[
RECORD_STACK_TRACE_SIZE];
00024
PEPROCESS gpepRecorded;
00025
PETHREAD gpetRecorded;
00026
00027
00028
DWORD gdwAllocFailIndex;
00029
00030
00031
DWORD gdwAllocsToFail = 1;
00032
00033
DWORD gdwFreeRecords;
00034
00035
00036
00037
00038 LPDWORD gparrTagsToFail;
00039 SIZE_T gdwTagsToFailCount;
00040
00041
00042
00043
00044
DWORD gdwFailRecords;
00045
DWORD gdwFailRecordCrtIndex;
00046
DWORD gdwFailRecordTotalFailures;
00047
00048
PPOOLRECORD gparrFailRecord;
00049
00050
00051
00052
00053
DWORD gdwFreeRecords;
00054
DWORD gdwFreeRecordCrtIndex;
00055
DWORD gdwFreeRecordTotalFrees;
00056
00057
PPOOLRECORD gparrFreeRecord;
00058
00059
FAST_MUTEX* gpAllocFastMutex;
00060
00061
Win32AllocStats gAllocList;
00062
00063
char gszTailAlloc[] =
"Win32kAlloc";
00064
#endif // POOL_INSTR
00065
00066
00067
00068 PVOID
Win32AllocPoolWithTagZInit(SIZE_T uBytes, ULONG uTag)
00069 {
00070 PVOID pv;
00071
00072 pv = Win32AllocPool(uBytes, uTag);
00073
if (pv) {
00074 RtlZeroMemory(pv, uBytes);
00075 }
00076
00077
return pv;
00078 }
00079
00080 PVOID
Win32AllocPoolWithQuotaTagZInit(SIZE_T uBytes, ULONG uTag)
00081 {
00082 PVOID pv;
00083
00084 pv = Win32AllocPoolWithQuota(uBytes, uTag);
00085
if (pv) {
00086 RtlZeroMemory(pv, uBytes);
00087 }
00088
00089
return pv;
00090 }
00091
00092 PVOID
UserReAllocPoolWithTag(
00093 PVOID pSrc,
00094 SIZE_T uBytesSrc,
00095 SIZE_T uBytes,
00096 ULONG iTag)
00097 {
00098 PVOID pDest;
00099
00100 pDest = UserAllocPool(uBytes, iTag);
00101
if (pDest !=
NULL) {
00102
00103
00104
00105
00106
if (uBytesSrc > uBytes) {
00107 uBytesSrc = uBytes;
00108 }
00109
00110 RtlCopyMemory(pDest, pSrc, uBytesSrc);
00111
00112 UserFreePool(pSrc);
00113 }
00114
00115
return pDest;
00116 }
00117
00118 PVOID
UserReAllocPoolWithQuotaTag(
00119 PVOID pSrc,
00120 SIZE_T uBytesSrc,
00121 SIZE_T uBytes,
00122 ULONG iTag)
00123 {
00124 PVOID pDest;
00125
00126 pDest = UserAllocPoolWithQuota(uBytes, iTag);
00127
if (pDest !=
NULL) {
00128
00129
00130
00131
00132
if (uBytesSrc > uBytes)
00133 uBytesSrc = uBytes;
00134
00135 RtlCopyMemory(pDest, pSrc, uBytesSrc);
00136
00137 UserFreePool(pSrc);
00138 }
00139
00140
return pDest;
00141 }
00142
00143
00144
00145
00146
00147 PVOID
UserRtlAllocMem(
00148 SIZE_T uBytes)
00149 {
00150
return UserAllocPool(uBytes, TAG_RTL);
00151 }
00152
00153 VOID UserRtlFreeMem(
00154 PVOID pMem)
00155 {
00156 UserFreePool(pMem);
00157 }
00158
00159
#ifdef POOL_INSTR
00160
00161
void RecordStackTrace(
void)
00162 {
00163 ULONG hash;
00164
00165 RtlZeroMemory(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE *
sizeof(PVOID));
00166
00167 GetStackTrace(2,
00168 RECORD_STACK_TRACE_SIZE,
00169 gRecordedStackTrace,
00170 &hash);
00171
00172 gpepRecorded =
PsGetCurrentProcess();
00173 gpetRecorded =
PsGetCurrentThread();
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
void RecordFailAllocation(
00184 ULONG tag,
00185 SIZE_T size)
00186 {
00187 ULONG hash;
00188
00189 UserAssert(gdwPoolFlags & POOL_KEEP_FAIL_RECORD);
00190
00191 gparrFailRecord[gdwFailRecordCrtIndex].
ExtraData = LongToPtr( tag );
00192 gparrFailRecord[gdwFailRecordCrtIndex].
size = size;
00193
00194 gdwFailRecordTotalFailures++;
00195
00196 RtlZeroMemory(gparrFailRecord[gdwFailRecordCrtIndex].trace,
00197 RECORD_STACK_TRACE_SIZE *
sizeof(PVOID));
00198
00199 GetStackTrace(2,
00200 RECORD_STACK_TRACE_SIZE,
00201 gparrFailRecord[gdwFailRecordCrtIndex].trace,
00202 &hash);
00203
00204 gdwFailRecordCrtIndex++;
00205
00206
if (gdwFailRecordCrtIndex >= gdwFailRecords) {
00207 gdwFailRecordCrtIndex = 0;
00208 }
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
void RecordFreePool(
00219 PVOID p,
00220 SIZE_T size)
00221 {
00222 ULONG hash;
00223
00224 UserAssert(gdwPoolFlags & POOL_KEEP_FREE_RECORD);
00225
00226 gparrFreeRecord[gdwFreeRecordCrtIndex].
ExtraData = p;
00227 gparrFreeRecord[gdwFreeRecordCrtIndex].
size = size;
00228
00229 gdwFreeRecordTotalFrees++;
00230
00231 RtlZeroMemory(gparrFreeRecord[gdwFreeRecordCrtIndex].trace,
00232 RECORD_STACK_TRACE_SIZE *
sizeof(PVOID));
00233
00234 GetStackTrace(2,
00235 RECORD_STACK_TRACE_SIZE,
00236 gparrFreeRecord[gdwFreeRecordCrtIndex].trace,
00237 &hash);
00238
00239 gdwFreeRecordCrtIndex++;
00240
00241
if (gdwFreeRecordCrtIndex >= gdwFreeRecords) {
00242 gdwFreeRecordCrtIndex = 0;
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 PVOID HeavyAllocPool(
00255 SIZE_T uBytes,
00256 ULONG tag,
00257 DWORD dwFlags)
00258 {
00259
DWORD* p;
00260 PWin32PoolHead ph;
00261
00262
00263
00264
00265
00266
if (!(
gdwPoolFlags &
POOL_HEAVY_ALLOCS)) {
00267
if (
dwFlags & DAP_USEQUOTA) {
00268
if (
dwFlags & DAP_NONPAGEDPOOL) {
00269 p =
ExAllocatePoolWithQuotaTag(SESSION_POOL_MASK | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
00270 uBytes,
00271 tag);
00272 }
else {
00273 p =
ExAllocatePoolWithQuotaTag(
00274 SESSION_POOL_MASK | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
00275 uBytes,
00276 tag);
00277 }
00278 }
else {
00279
if (
dwFlags & DAP_NONPAGEDPOOL) {
00280 p =
ExAllocatePoolWithTag(SESSION_POOL_MASK | NonPagedPool, uBytes, tag);
00281 }
else {
00282 p =
ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool, uBytes, tag);
00283 }
00284 }
00285
00286
if (p !=
NULL && (
dwFlags & DAP_ZEROINIT)) {
00287 RtlZeroMemory(p, uBytes);
00288 }
00289
00290
return p;
00291 }
00292
00293
00294
00295
00296
if (uBytes >= MAXULONG -
sizeof(Win32PoolHead) -
sizeof(gszTailAlloc)) {
00297
00298
if (
gdwPoolFlags &
POOL_KEEP_FAIL_RECORD) {
00299 RecordFailAllocation(tag, 0);
00300 }
00301
return NULL;
00302 }
00303
00304
00305
00306
00307
KeEnterCriticalRegion();
00308
ExAcquireFastMutexUnsafe(gpAllocFastMutex);
00309
00310
#ifdef POOL_INSTR_API
00311
00312
00313
00314
00315
if (
gdwPoolFlags &
POOL_FAIL_ALLOCS
00316
#if DBG
00317
&& (tag != TAG_GLOBALTHREADLOCK)
00318
#endif // DBG
00319
) {
00320
00321
00322 SIZE_T dwInd;
00323
00324
for (dwInd = 0; dwInd < gdwTagsToFailCount; dwInd++) {
00325
if (tag == gparrTagsToFail[dwInd]) {
00326
break;
00327 }
00328 }
00329
00330
if (dwInd < gdwTagsToFailCount) {
00331
if (
gdwPoolFlags &
POOL_KEEP_FAIL_RECORD) {
00332 RecordFailAllocation(tag, uBytes);
00333 }
00334
00335 RIPMSG0(RIP_WARNING,
"Pool allocation failed because of global restriction");
00336 p =
NULL;
00337
goto exit;
00338 }
00339 }
00340
#endif // POOL_INSTR_API
00341
00342
#if DBG
00343
if ((
gdwPoolFlags &
POOL_FAIL_BY_INDEX) && (tag != TAG_GLOBALTHREADLOCK)) {
00344
00345
00346
00347
00348 gdwAllocCrt++;
00349
00350
if (gdwAllocCrt >= gdwAllocFailIndex &&
00351 gdwAllocCrt < gdwAllocFailIndex + gdwAllocsToFail) {
00352
00353 RecordStackTrace();
00354
00355 KdPrint((
"\n--------------------------------------------------\n"));
00356 KdPrint((
00357
"\nPool allocation %d failed because of registry settings",
00358 gdwAllocCrt));
00359 KdPrint((
"\n--------------------------------------------------\n\n"));
00360
00361
if (
gdwPoolFlags &
POOL_KEEP_FAIL_RECORD) {
00362 RecordFailAllocation(tag, uBytes);
00363 }
00364 p =
NULL;
00365
goto exit;
00366 }
00367 }
00368
#endif // DBG
00369
00370
00371
00372
00373 uBytes +=
sizeof(Win32PoolHead);
00374
00375
if (
gdwPoolFlags &
POOL_TAIL_CHECK) {
00376 uBytes +=
sizeof(gszTailAlloc);
00377 }
00378
00379
if (
dwFlags & DAP_USEQUOTA) {
00380
if (
dwFlags & DAP_NONPAGEDPOOL) {
00381 p =
ExAllocatePoolWithQuotaTag(SESSION_POOL_MASK | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
00382 uBytes,
00383 tag);
00384 }
else {
00385 p =
ExAllocatePoolWithQuotaTag(
00386 SESSION_POOL_MASK | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
00387 uBytes,
00388 tag);
00389 }
00390 }
else {
00391
if (
dwFlags & DAP_NONPAGEDPOOL) {
00392 p =
ExAllocatePoolWithTag(SESSION_POOL_MASK | NonPagedPool, uBytes, tag);
00393 }
else {
00394 p =
ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool, uBytes, tag);
00395 }
00396 }
00397
00398
00399
00400
00401
if (p ==
NULL) {
00402
00403
if (
gdwPoolFlags &
POOL_KEEP_FAIL_RECORD) {
00404
00405 uBytes -=
sizeof(Win32PoolHead);
00406
00407
if (
gdwPoolFlags &
POOL_TAIL_CHECK) {
00408 uBytes -=
sizeof(gszTailAlloc);
00409 }
00410
00411 RecordFailAllocation(tag, uBytes);
00412 }
00413
00414
goto exit;
00415 }
00416
00417 uBytes -=
sizeof(Win32PoolHead);
00418
00419
if (
gdwPoolFlags &
POOL_TAIL_CHECK) {
00420 uBytes -=
sizeof(gszTailAlloc);
00421
00422 RtlCopyMemory(((BYTE*)p) + uBytes, gszTailAlloc,
sizeof(gszTailAlloc));
00423 }
00424
00425
00426
00427
00428 ph = (PWin32PoolHead)p;
00429
00430 p += (
sizeof(Win32PoolHead) /
sizeof(
DWORD));
00431
00432
00433
00434
00435 gAllocList.
dwCrtMem += uBytes;
00436
00437
if (gAllocList.
dwMaxMem < gAllocList.
dwCrtMem) {
00438 gAllocList.
dwMaxMem = gAllocList.
dwCrtMem;
00439 }
00440
00441 (gAllocList.
dwCrtAlloc)++;
00442
00443
if (gAllocList.
dwMaxAlloc < gAllocList.
dwCrtAlloc) {
00444 gAllocList.
dwMaxAlloc = gAllocList.
dwCrtAlloc;
00445 }
00446
00447
00448
00449
00450
if (
gdwPoolFlags &
POOL_CAPTURE_STACK) {
00451 ph->pTrace =
ExAllocatePoolWithTag(SESSION_POOL_MASK | PagedPool,
00452 POOL_ALLOC_TRACE_SIZE *
sizeof(PVOID),
00453 TAG_STACK);
00454
00455
if (ph->pTrace !=
NULL) {
00456
00457 ULONG hash;
00458
00459 RtlZeroMemory(ph->pTrace, POOL_ALLOC_TRACE_SIZE *
sizeof(PVOID));
00460
00461 GetStackTrace(1,
00462 POOL_ALLOC_TRACE_SIZE,
00463 ph->pTrace,
00464 &hash);
00465 }
00466 }
else {
00467 ph->pTrace =
NULL;
00468 }
00469
00470
00471
00472
00473 ph->size = uBytes;
00474
00475
00476
00477
00478 ph->pPrev =
NULL;
00479 ph->pNext = gAllocList.
pHead;
00480
00481
if (gAllocList.
pHead !=
NULL)
00482 gAllocList.
pHead->pPrev = ph;
00483
00484 gAllocList.
pHead = ph;
00485
00486
if (
dwFlags & DAP_ZEROINIT) {
00487 RtlZeroMemory(p, uBytes);
00488 }
00489
00490
exit:
00491
00492
00493
00494
ExReleaseFastMutexUnsafe(gpAllocFastMutex);
00495
KeLeaveCriticalRegion();
00496
00497
return p;
00498 }
00499
00500
00501
00502
00503
00504
00505
void HeavyFreePool(
00506 PVOID p)
00507 {
00508 SIZE_T uBytes;
00509 PWin32PoolHead ph;
00510
00511
00512
00513
00514
00515
if (!(
gdwPoolFlags &
POOL_HEAVY_ALLOCS)) {
00516
ExFreePool(p);
00517
return;
00518 }
00519
00520
00521
00522
00523
KeEnterCriticalRegion();
00524
ExAcquireFastMutexUnsafe(gpAllocFastMutex);
00525
00526 ph = (PWin32PoolHead)((
DWORD*)p - (
sizeof(Win32PoolHead) /
sizeof(
DWORD)));
00527
00528 uBytes = ph->size;
00529
00530
00531
00532
00533
if (
gdwPoolFlags &
POOL_TAIL_CHECK) {
00534
if (!RtlEqualMemory((BYTE*)p + uBytes, gszTailAlloc,
sizeof(gszTailAlloc))) {
00535 RIPMSG1(RIP_ERROR,
"POOL CORRUPTION for %#p", p);
00536 }
00537 }
00538
00539 gAllocList.
dwCrtMem -= uBytes;
00540
00541 UserAssert(gAllocList.
dwCrtAlloc > 0);
00542
00543 (gAllocList.
dwCrtAlloc)--;
00544
00545
00546
00547
00548
if (ph->pPrev ==
NULL) {
00549
if (ph->pNext ==
NULL) {
00550
00551 UserAssert(gAllocList.
dwCrtAlloc == 0);
00552
00553 gAllocList.
pHead =
NULL;
00554 }
else {
00555 ph->pNext->pPrev =
NULL;
00556 gAllocList.
pHead = ph->pNext;
00557 }
00558 }
else {
00559 ph->pPrev->pNext = ph->pNext;
00560
if (ph->pNext !=
NULL) {
00561 ph->pNext->pPrev = ph->pPrev;
00562 }
00563 }
00564
00565
00566
00567
00568
if (ph->pTrace !=
NULL) {
00569
ExFreePool(ph->pTrace);
00570 }
00571
00572
if (
gdwPoolFlags &
POOL_KEEP_FREE_RECORD) {
00573 RecordFreePool(ph, ph->size);
00574 }
00575
00576
ExFreePool(ph);
00577
00578
00579
00580
00581
ExReleaseFastMutexUnsafe(gpAllocFastMutex);
00582
KeLeaveCriticalRegion();
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
void CleanupPoolAllocations(
00592
void)
00593 {
00594 PWin32PoolHead pHead;
00595 PWin32PoolHead pNext;
00596
00597
if (gAllocList.
dwCrtAlloc != 0) {
00598
00599
if ((
gdwPoolFlags &
POOL_BREAK_FOR_LEAKS) &&
00600 **((PBOOLEAN*)&
KdDebuggerEnabled)) {
00601
00602
00603
00604
00605
00606
#undef DbgPrint
00607
DbgPrint(
"\n------------------------\n"
00608
"There is still pool memory not freed in win32k.sys !!!\n"
00609
"Use !dpa -vs to dump it\n"
00610
"-------------------------\n");
00611 DbgBreakPoint();
00612 }
00613
00614 pHead = gAllocList.
pHead;
00615
00616
while (pHead !=
NULL) {
00617
00618 pNext = pHead->pNext;
00619
00620 UserFreePool(pHead + 1);
00621
00622 pHead = pNext;
00623 }
00624 }
00625 }
00626
00627
00628
00629
00630
00631
void CleanUpPoolLimitations(
void)
00632 {
00633
if (gpAllocFastMutex !=
NULL) {
00634
ExFreePool(gpAllocFastMutex);
00635 gpAllocFastMutex =
NULL;
00636 }
00637
00638
if (gparrFailRecord !=
NULL) {
00639
ExFreePool(gparrFailRecord);
00640 gparrFailRecord =
NULL;
00641 }
00642
00643
if (gparrFreeRecord !=
NULL) {
00644
ExFreePool(gparrFreeRecord);
00645 gparrFreeRecord =
NULL;
00646 }
00647
00648
if (gparrTagsToFail !=
NULL) {
00649
ExFreePool(gparrTagsToFail);
00650 gparrTagsToFail =
NULL;
00651 }
00652
00653 }
00654
00655
00656
00657
00658
00659
00660
void InitPoolLimitations(
void)
00661 {
00662 UNICODE_STRING UnicodeString;
00663 OBJECT_ATTRIBUTES
ObjectAttributes;
00664 HANDLE hkey;
00665
NTSTATUS Status;
00666 WCHAR achKeyName[512];
00667 WCHAR achKeyValue[512];
00668
DWORD dwData;
00669 ULONG ucb;
00670
00671
00672
00673
00674
00675 gpAllocFastMutex =
ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
00676
sizeof(
FAST_MUTEX),
00677 TAG_DEBUG);
00678
00679 UserAssert(gpAllocFastMutex != NULL);
00680
00681
ExInitializeFastMutex(gpAllocFastMutex);
00682
00683
00684
00685
00686
if (
gbRemoteSession) {
00687
gdwPoolFlags =
POOL_HEAVY_ALLOCS;
00688
00689
#if DBG
00690
gdwPoolFlags |= (
POOL_CAPTURE_STACK |
POOL_BREAK_FOR_LEAKS);
00691
#endif // DBG
00692
}
00693
00694
00695
00696
00697
RtlInitUnicodeString(
00698 &UnicodeString,
00699 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SubSystems\\Pool");
00700
00701 InitializeObjectAttributes(
00702 &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
00703
00704
Status = ZwOpenKey(&hkey, KEY_READ, &ObjectAttributes);
00705
if (!
NT_SUCCESS(Status)) {
00706
00707
#if DBG
00708
00709
00710
00711
if (
gbRemoteSession) {
00712
00713 gparrFailRecord =
ExAllocatePoolWithTag(PagedPool,
00714 32 *
sizeof(
POOLRECORD),
00715 TAG_DEBUG);
00716
00717
if (gparrFailRecord !=
NULL) {
00718 gdwFailRecords = 32;
00719
gdwPoolFlags |=
POOL_KEEP_FAIL_RECORD;
00720 }
00721
00722 gparrFreeRecord =
ExAllocatePoolWithTag(PagedPool,
00723 32 *
sizeof(
POOLRECORD),
00724 TAG_DEBUG);
00725
00726
if (gparrFreeRecord !=
NULL) {
00727 gdwFreeRecords = 32;
00728
gdwPoolFlags |=
POOL_KEEP_FREE_RECORD;
00729 }
00730 }
00731
#endif // DBG
00732
00733
return;
00734 }
00735
00736
if (
gbRemoteSession) {
00737
00738
00739
00740
00741
RtlInitUnicodeString(&UnicodeString, L
"BreakForPoolLeaks");
00742
00743
Status = ZwQueryValueKey(
00744 hkey,
00745 &UnicodeString,
00746 KeyValuePartialInformation,
00747 &achKeyValue,
00748
sizeof(achKeyValue),
00749 &ucb);
00750
00751
if (
NT_SUCCESS(Status) &&
00752 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00753
00754 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00755
00756
if (dwData != 0) {
00757
gdwPoolFlags |=
POOL_BREAK_FOR_LEAKS;
00758 }
else {
00759
gdwPoolFlags &= ~
POOL_BREAK_FOR_LEAKS;
00760 }
00761 }
00762
00763
00764
00765
00766
RtlInitUnicodeString(&UnicodeString, L
"HeavyRemoteSession");
00767
00768
Status = ZwQueryValueKey(
00769 hkey,
00770 &UnicodeString,
00771 KeyValuePartialInformation,
00772 &achKeyValue,
00773
sizeof(achKeyValue),
00774 &ucb);
00775
00776
if (
NT_SUCCESS(Status) &&
00777 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00778
00779 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00780
00781
if (dwData == 0) {
00782
gdwPoolFlags &= ~
POOL_HEAVY_ALLOCS;
00783 }
00784 }
00785 }
else {
00786
00787
00788
00789
00790
RtlInitUnicodeString(&UnicodeString, L
"HeavyConsoleSession");
00791
00792
Status = ZwQueryValueKey(
00793 hkey,
00794 &UnicodeString,
00795 KeyValuePartialInformation,
00796 &achKeyValue,
00797
sizeof(achKeyValue),
00798 &ucb);
00799
00800
if (
NT_SUCCESS(Status) &&
00801 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00802
00803 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00804
00805
if (dwData != 0) {
00806
gdwPoolFlags |=
POOL_HEAVY_ALLOCS;
00807 }
00808 }
00809 }
00810
00811
if (!(
gdwPoolFlags &
POOL_HEAVY_ALLOCS)) {
00812 ZwClose(hkey);
00813
return;
00814 }
00815
00816
00817
00818
00819
RtlInitUnicodeString(&UnicodeString, L
"StackTraces");
00820
00821 RtlZeroMemory(achKeyName,
sizeof(achKeyName));
00822
00823
Status = ZwQueryValueKey(
00824 hkey,
00825 &UnicodeString,
00826 KeyValuePartialInformation,
00827 &achKeyValue,
00828
sizeof(achKeyValue),
00829 &ucb);
00830
00831
if (
NT_SUCCESS(Status) &&
00832 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00833
00834 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00835
00836
if (dwData == 0) {
00837
gdwPoolFlags &= ~
POOL_CAPTURE_STACK;
00838 }
else {
00839
gdwPoolFlags |=
POOL_CAPTURE_STACK;
00840 }
00841 }
00842
00843
00844
00845
00846
RtlInitUnicodeString(&UnicodeString, L
"UseTailString");
00847
00848
Status = ZwQueryValueKey(
00849 hkey,
00850 &UnicodeString,
00851 KeyValuePartialInformation,
00852 &achKeyValue,
00853
sizeof(achKeyValue),
00854 &ucb);
00855
00856
if (
NT_SUCCESS(Status) &&
00857 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00858
00859 dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00860
00861
if (dwData != 0) {
00862
gdwPoolFlags |=
POOL_TAIL_CHECK;
00863 }
00864 }
00865
00866
00867
00868
00869
#if DBG
00870
gdwFreeRecords = 32;
00871
#endif // DBG
00872
00873
RtlInitUnicodeString(&UnicodeString, L
"KeepFreeRecords");
00874
00875
Status = ZwQueryValueKey(
00876 hkey,
00877 &UnicodeString,
00878 KeyValuePartialInformation,
00879 &achKeyValue,
00880
sizeof(achKeyValue),
00881 &ucb);
00882
00883
if (
NT_SUCCESS(Status) &&
00884 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00885
00886 gdwFreeRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00887 }
00888
00889
if (gdwFreeRecords != 0) {
00890
00891 gparrFreeRecord =
ExAllocatePoolWithTag(PagedPool,
00892 gdwFreeRecords *
sizeof(
POOLRECORD),
00893 TAG_DEBUG);
00894
00895
if (gparrFreeRecord !=
NULL) {
00896
gdwPoolFlags |=
POOL_KEEP_FREE_RECORD;
00897 }
00898 }
00899
00900
00901
00902
00903
#if DBG
00904
gdwFailRecords = 32;
00905
#endif // DBG
00906
00907
RtlInitUnicodeString(&UnicodeString, L
"KeepFailRecords");
00908
00909
Status = ZwQueryValueKey(
00910 hkey,
00911 &UnicodeString,
00912 KeyValuePartialInformation,
00913 &achKeyValue,
00914
sizeof(achKeyValue),
00915 &ucb);
00916
00917
if (
NT_SUCCESS(Status) &&
00918 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00919
00920 gdwFailRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00921 }
00922
00923
if (gdwFailRecords != 0) {
00924
00925 gparrFailRecord =
ExAllocatePoolWithTag(PagedPool,
00926 gdwFailRecords *
sizeof(
POOLRECORD),
00927 TAG_DEBUG);
00928
00929
if (gparrFailRecord !=
NULL) {
00930
gdwPoolFlags |=
POOL_KEEP_FAIL_RECORD;
00931 }
00932 }
00933
00934
#if DBG
00935
00936
00937
00938
RtlInitUnicodeString(&UnicodeString, L
"AllocationIndex");
00939
00940
Status = ZwQueryValueKey(
00941 hkey,
00942 &UnicodeString,
00943 KeyValuePartialInformation,
00944 &achKeyValue,
00945
sizeof(achKeyValue),
00946 &ucb);
00947
00948
if (
NT_SUCCESS(Status) &&
00949 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00950
00951 gdwAllocFailIndex = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00952 }
00953
00954
00955
RtlInitUnicodeString(&UnicodeString, L
"AllocationsToFail");
00956
00957
Status = ZwQueryValueKey(
00958 hkey,
00959 &UnicodeString,
00960 KeyValuePartialInformation,
00961 &achKeyValue,
00962
sizeof(achKeyValue),
00963 &ucb);
00964
00965
if (
NT_SUCCESS(Status) &&
00966 ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
00967
00968 gdwAllocsToFail = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
00969 }
00970
00971
if (gdwAllocFailIndex != 0 && gdwAllocsToFail > 0) {
00972
gdwPoolFlags |=
POOL_FAIL_BY_INDEX;
00973 }
00974
#endif // DBG
00975
00976 ZwClose(hkey);
00977
00978
return;
00979 }
00980
#endif // POOL_INSTR
00981
00982
#ifdef POOL_INSTR_API
00983
00984
BOOL _Win32PoolAllocationStats(
00985 LPDWORD parrTags,
00986 SIZE_T tagsCount,
00987 SIZE_T* lpdwMaxMem,
00988 SIZE_T* lpdwCrtMem,
00989 LPDWORD lpdwMaxAlloc,
00990 LPDWORD lpdwCrtAlloc)
00991 {
00992
BOOL bRet =
FALSE;
00993
00994
00995
00996
00997
if (!(
gdwPoolFlags &
POOL_HEAVY_ALLOCS)) {
00998
return FALSE;
00999 }
01000
01001 *lpdwMaxMem = gAllocList.
dwMaxMem;
01002 *lpdwCrtMem = gAllocList.
dwCrtMem;
01003 *lpdwMaxAlloc = gAllocList.
dwMaxAlloc;
01004 *lpdwCrtAlloc = gAllocList.
dwCrtAlloc;
01005
01006
01007
01008
01009
KeEnterCriticalRegion();
01010
ExAcquireFastMutexUnsafe(gpAllocFastMutex);
01011
01012
if (gparrTagsToFail !=
NULL) {
01013
ExFreePool(gparrTagsToFail);
01014 gparrTagsToFail =
NULL;
01015 gdwTagsToFailCount = 0;
01016 }
01017
01018
if (tagsCount != 0) {
01019
gdwPoolFlags |=
POOL_FAIL_ALLOCS;
01020
01021
if (tagsCount > MAX_TAGS_TO_FAIL) {
01022 gdwTagsToFailCount = 0xFFFFFFFF;
01023 RIPMSG0(RIP_WARNING,
"All pool allocations in WIN32K.SYS will fail !!!");
01024 bRet =
TRUE;
01025
goto exit;
01026 }
01027
01028 }
else {
01029
gdwPoolFlags &= ~
POOL_FAIL_ALLOCS;
01030
01031 RIPMSG0(RIP_WARNING,
"Pool allocations in WIN32K.SYS back to normal !");
01032 bRet =
TRUE;
01033
goto exit;
01034 }
01035
01036 gparrTagsToFail =
ExAllocatePoolWithTag(PagedPool,
01037
sizeof(DWORD) * tagsCount,
01038 TAG_DEBUG);
01039
01040
if (gparrTagsToFail ==
NULL) {
01041
gdwPoolFlags &= ~
POOL_FAIL_ALLOCS;
01042 RIPMSG0(RIP_WARNING,
"Pool allocations in WIN32K.SYS back to normal !");
01043
goto exit;
01044 }
01045
01046
try {
01047
ProbeForRead(parrTags,
sizeof(DWORD) * tagsCount, DATAALIGN);
01048
01049 RtlCopyMemory(gparrTagsToFail, parrTags,
sizeof(DWORD) * tagsCount);
01050
01051 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
01052
01053
if (gparrTagsToFail !=
NULL) {
01054
ExFreePool(gparrTagsToFail);
01055 gparrTagsToFail =
NULL;
01056
01057
gdwPoolFlags &= ~
POOL_FAIL_ALLOCS;
01058 RIPMSG0(RIP_WARNING,
"Pool allocations in WIN32K.SYS back to normal !");
01059
goto exit;
01060 }
01061 }
01062 gdwTagsToFailCount = tagsCount;
01063
01064 RIPMSG0(RIP_WARNING,
"Specific pool allocations in WIN32K.SYS will fail !!!");
01065
01066
exit:
01067
01068
01069
01070
ExReleaseFastMutexUnsafe(gpAllocFastMutex);
01071
KeLeaveCriticalRegion();
01072
01073
return TRUE;
01074 }
01075
01076
#endif // POOL_INSTR_API
01077
01078
#ifdef TRACE_MAP_VIEWS
01079
01080
FAST_MUTEX* gpSectionFastMutex;
01081 PWin32Section gpSections;
01082
01083
#define EnterSectionCrit() \
01084
KeEnterCriticalRegion(); \
01085
ExAcquireFastMutexUnsafe(gpSectionFastMutex);
01086
01087
#define LeaveSectionCrit() \
01088
ExReleaseFastMutexUnsafe(gpSectionFastMutex); \
01089
KeLeaveCriticalRegion();
01090
01091
01092
01093
01094
01095
01096
void CleanUpSections(
void)
01097 {
01098
if (gpSectionFastMutex) {
01099
ExFreePool(gpSectionFastMutex);
01100 gpSectionFastMutex =
NULL;
01101 }
01102 }
01103
01104
VOID InitSectionTrace(VOID)
01105 {
01106 gpSectionFastMutex =
ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
01107
sizeof(
FAST_MUTEX),
01108 TAG_DEBUG);
01109
01110 UserAssert(gpSectionFastMutex != NULL);
01111
01112
ExInitializeFastMutex(gpSectionFastMutex);
01113 }
01114
01115
NTSTATUS _Win32CreateSection(
01116 PVOID* pSectionObject,
01117 ACCESS_MASK DesiredAccess,
01118 POBJECT_ATTRIBUTES ObjectAttributes,
01119 PLARGE_INTEGER pInputMaximumSize,
01120 ULONG SectionPageProtection,
01121 ULONG AllocationAttributes,
01122 HANDLE FileHandle,
01123
PFILE_OBJECT FileObject,
01124 DWORD SectionTag)
01125 {
01126 PWin32Section pSection;
01127
NTSTATUS Status;
01128
01129
#ifdef MAP_VIEW_STACK_TRACE
01130
ULONG hash;
01131
#endif
01132
01133
Status =
MmCreateSection(
01134 pSectionObject,
01135 DesiredAccess,
01136 ObjectAttributes,
01137 pInputMaximumSize,
01138 SectionPageProtection,
01139 AllocationAttributes,
01140 FileHandle,
01141 FileObject);
01142
01143
if (!
NT_SUCCESS(Status)) {
01144 RIPMSG1(RIP_WARNING,
"MmCreateSection failed with Statu %x", Status);
01145 *pSectionObject =
NULL;
01146
return Status;
01147 }
01148
01149 pSection = UserAllocPoolZInit(
sizeof(Win32Section), TAG_SECTION);
01150
01151
if (pSection ==
NULL) {
01152
ObDereferenceObject(*pSectionObject);
01153 RIPMSG0(RIP_WARNING,
"Failed to allocate memory for section");
01154 *pSectionObject =
NULL;
01155
return STATUS_UNSUCCESSFUL;
01156 }
01157
01158 EnterSectionCrit();
01159
01160 pSection->pNext = gpSections;
01161
if (gpSections !=
NULL) {
01162 UserAssert(gpSections->pPrev == NULL);
01163 gpSections->pPrev = pSection;
01164 }
01165
01166 pSection->SectionObject = *pSectionObject;
01167 pSection->SectionSize = *pInputMaximumSize;
01168 pSection->SectionTag = SectionTag;
01169
01170 gpSections = pSection;
01171
01172
#ifdef MAP_VIEW_STACK_TRACE
01173
RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE *
sizeof(PVOID));
01174
01175 GetStackTrace(1,
01176 MAP_VIEW_STACK_TRACE_SIZE,
01177 pSection->trace,
01178 &hash);
01179
01180
#endif // MAP_VIEW_STACK_TRACE
01181
01182 LeaveSectionCrit();
01183
01184
return STATUS_SUCCESS;
01185
01186 }
01187
01188
VOID _Win32DestroySection(
01189 PVOID Section)
01190 {
01191 PWin32Section ps;
01192
01193 EnterSectionCrit();
01194
01195 ps = gpSections;
01196
01197
while (ps !=
NULL) {
01198
if (ps->SectionObject == Section) {
01199
01200
01201
01202
01203
if (ps->pFirstView !=
NULL) {
01204 RIPMSG1(RIP_ERROR,
"Section %#p still has views", ps);
01205 }
01206
01207
01208
01209
01210
if (ps->pPrev ==
NULL) {
01211
01212 UserAssert(ps == gpSections);
01213
01214 gpSections = ps->pNext;
01215
01216
if (ps->pNext !=
NULL) {
01217 ps->pNext->pPrev =
NULL;
01218 }
01219 }
else {
01220 ps->pPrev->pNext = ps->pNext;
01221
if (ps->pNext !=
NULL) {
01222 ps->pNext->pPrev = ps->pPrev;
01223 }
01224 }
01225
ObDereferenceObject(Section);
01226 UserFreePool(ps);
01227 LeaveSectionCrit();
01228
return;
01229 }
01230 ps = ps->pNext;
01231 }
01232
01233 RIPMSG1(RIP_ERROR,
"Cannot find Section %#p", Section);
01234 LeaveSectionCrit();
01235 }
01236
01237
NTSTATUS _Win32MapViewInSessionSpace(
01238 PVOID Section,
01239 PVOID* pMappedBase,
01240 PSIZE_T pViewSize)
01241 {
01242
NTSTATUS Status;
01243 PWin32Section ps;
01244 PWin32MapView pMapView;
01245
01246
#ifdef MAP_VIEW_STACK_TRACE
01247
ULONG hash;
01248
#endif
01249
01250
01251
01252
01253
Status =
MmMapViewInSessionSpace(Section, pMappedBase, pViewSize);
01254
01255
if (!
NT_SUCCESS(Status)) {
01256 RIPMSG1(RIP_WARNING,
"MmMapViewInSessionSpace failed with Status %x",
01257 Status);
01258 *pMappedBase =
NULL;
01259
return Status;
01260 }
01261
01262
01263
01264
01265 pMapView = UserAllocPoolZInit(
sizeof(Win32MapView), TAG_SECTION);
01266
01267
if (pMapView ==
NULL) {
01268 RIPMSG0(RIP_WARNING,
"_Win32MapViewInSessionSpace: Memory failure");
01269
01270
MmUnmapViewInSessionSpace(*pMappedBase);
01271 *pMappedBase =
NULL;
01272
return STATUS_NO_MEMORY;
01273 }
01274
01275 pMapView->pViewBase = *pMappedBase;
01276 pMapView->ViewSize = *pViewSize;
01277
01278 EnterSectionCrit();
01279
01280 ps = gpSections;
01281
01282
while (ps !=
NULL) {
01283
if (ps->SectionObject == Section) {
01284
01285 pMapView->pSection = ps;
01286
01287 pMapView->pNext = ps->pFirstView;
01288
01289
if (ps->pFirstView !=
NULL) {
01290 ps->pFirstView->pPrev = pMapView;
01291 }
01292 ps->pFirstView = pMapView;
01293
01294
#ifdef MAP_VIEW_STACK_TRACE
01295
RtlZeroMemory(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE *
sizeof(PVOID));
01296
01297 GetStackTrace(1,
01298 MAP_VIEW_STACK_TRACE_SIZE,
01299 pMapView->trace,
01300 &hash);
01301
01302
#endif // MAP_VIEW_STACK_TRACE
01303
01304 LeaveSectionCrit();
01305
return STATUS_SUCCESS;
01306 }
01307 ps = ps->pNext;
01308 }
01309
01310 RIPMSG1(RIP_ERROR,
"_Win32MapViewInSessionSpace: Could not find section for %#p",
01311 Section);
01312
01313 LeaveSectionCrit();
01314
01315
return STATUS_UNSUCCESSFUL;
01316 }
01317
01318
NTSTATUS _Win32UnmapViewInSessionSpace(
01319 PVOID MappedBase)
01320 {
01321 PWin32Section ps;
01322 PWin32MapView pv;
01323
NTSTATUS Status;
01324
01325 EnterSectionCrit();
01326
01327 ps = gpSections;
01328
01329
while (ps !=
NULL) {
01330
01331 pv = ps->pFirstView;
01332
01333
while (pv !=
NULL) {
01334
01335 UserAssert(pv->pSection == ps);
01336
01337
if (pv->pViewBase == MappedBase) {
01338
01339
01340
01341
if (pv->pPrev ==
NULL) {
01342
01343 UserAssert(pv == ps->pFirstView);
01344
01345 ps->pFirstView = pv->pNext;
01346
01347
if (pv->pNext !=
NULL) {
01348 pv->pNext->pPrev =
NULL;
01349 }
01350 }
else {
01351 pv->pPrev->pNext = pv->pNext;
01352
if (pv->pNext !=
NULL) {
01353 pv->pNext->pPrev = pv->pPrev;
01354 }
01355 }
01356
01357 UserFreePool(pv);
01358
01359
Status =
MmUnmapViewInSessionSpace(MappedBase);
01360
01361 LeaveSectionCrit();
01362
01363
return Status;
01364 }
01365 pv = pv->pNext;
01366 }
01367 ps = ps->pNext;
01368 }
01369
01370 RIPMSG1(RIP_ERROR,
"_Win32UnmapViewInSessionSpace: Could not find view for %#p",
01371 MappedBase);
01372
01373 LeaveSectionCrit();
01374
01375
return STATUS_UNSUCCESSFUL;
01376 }
01377
01378
#endif // TRACE_MAP_VIEWS