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.

1461 lines
38 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: pool.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Pool reallocation routines
  7. *
  8. * History:
  9. * 03-04-95 JimA Created.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. DWORD gdwPoolFlags;
  14. DWORD gSessionPoolMask;
  15. #ifdef POOL_INSTR
  16. /*
  17. * Globals used by RecordStackTrace
  18. */
  19. PVOID gRecordedStackTrace[RECORD_STACK_TRACE_SIZE];
  20. PEPROCESS gpepRecorded;
  21. PETHREAD gpetRecorded;
  22. DWORD gdwAllocFailIndex; // the index of the allocation that's
  23. // going to fail
  24. DWORD gdwAllocsToFail = 1; // how many allocs to fail
  25. DWORD gdwFreeRecords;
  26. /*
  27. * Targeted tag failures
  28. */
  29. LPDWORD gparrTagsToFail;
  30. SIZE_T gdwTagsToFailCount;
  31. /*
  32. * Support to keep records of failed pool allocations
  33. */
  34. DWORD gdwFailRecords;
  35. DWORD gdwFailRecordCrtIndex;
  36. DWORD gdwFailRecordTotalFailures;
  37. PPOOLRECORD gparrFailRecord;
  38. /*
  39. * Support to keep records of pool free
  40. */
  41. DWORD gdwFreeRecords;
  42. DWORD gdwFreeRecordCrtIndex;
  43. DWORD gdwFreeRecordTotalFrees;
  44. PPOOLRECORD gparrFreeRecord;
  45. FAST_MUTEX* gpAllocFastMutex; // mutex to syncronize pool allocations
  46. Win32AllocStats gAllocList;
  47. CONST char gszTailAlloc[] = "Win32kAlloc";
  48. #define USESESSION(dwFlags) (((dwFlags & DAP_NONSESSION) != 0) ? 0 : gSessionPoolMask)
  49. #endif
  50. /***************************************************************************\
  51. * Win32QueryPoolSize
  52. *
  53. * Returns the size of the given pool block.
  54. *
  55. * 08-17-2001 JasonSch Created.
  56. \***************************************************************************/
  57. SIZE_T Win32QueryPoolSize(
  58. PVOID p)
  59. {
  60. /*
  61. * If POOL_HEAVY_ALLOCS is not defined then the pointer is what
  62. * we allocated.
  63. */
  64. if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) {
  65. BOOLEAN notUsed;
  66. return ExQueryPoolBlockSize(p, &notUsed);
  67. } else {
  68. PWin32PoolHead ph;
  69. ph = (PWin32PoolHead)((DWORD*)p - (sizeof(Win32PoolHead) / sizeof(DWORD)));
  70. return ph->size;
  71. }
  72. }
  73. PVOID Win32AllocPoolWithTagZInit(SIZE_T uBytes, ULONG uTag)
  74. {
  75. PVOID pv;
  76. pv = Win32AllocPool(uBytes, uTag);
  77. if (pv) {
  78. RtlZeroMemory(pv, uBytes);
  79. }
  80. return pv;
  81. }
  82. PVOID Win32AllocPoolWithTagZInitWithPriority(SIZE_T uBytes, ULONG uTag, EX_POOL_PRIORITY priority)
  83. {
  84. PVOID pv;
  85. pv = Win32AllocPoolWithPriority(uBytes, uTag, priority);
  86. if (pv) {
  87. RtlZeroMemory(pv, uBytes);
  88. }
  89. return pv;
  90. }
  91. PVOID Win32AllocPoolWithQuotaTagZInit(SIZE_T uBytes, ULONG uTag)
  92. {
  93. PVOID pv;
  94. pv = Win32AllocPoolWithQuota(uBytes, uTag);
  95. if (pv) {
  96. RtlZeroMemory(pv, uBytes);
  97. }
  98. return pv;
  99. }
  100. PVOID UserReAllocPoolWithTag(
  101. PVOID pSrc,
  102. SIZE_T uBytesSrc,
  103. SIZE_T uBytes,
  104. ULONG iTag)
  105. {
  106. PVOID pDest;
  107. pDest = UserAllocPool(uBytes, iTag);
  108. if (pDest != NULL) {
  109. /*
  110. * If the block is shrinking, don't copy too many bytes.
  111. */
  112. if (uBytesSrc > uBytes) {
  113. uBytesSrc = uBytes;
  114. }
  115. RtlCopyMemory(pDest, pSrc, uBytesSrc);
  116. UserFreePool(pSrc);
  117. }
  118. return pDest;
  119. }
  120. PVOID UserReAllocPoolWithQuotaTag(
  121. PVOID pSrc,
  122. SIZE_T uBytesSrc,
  123. SIZE_T uBytes,
  124. ULONG iTag)
  125. {
  126. PVOID pDest;
  127. pDest = UserAllocPoolWithQuota(uBytes, iTag);
  128. if (pDest != NULL) {
  129. /*
  130. * If the block is shrinking, don't copy too many bytes.
  131. */
  132. if (uBytesSrc > uBytes)
  133. uBytesSrc = uBytes;
  134. RtlCopyMemory(pDest, pSrc, uBytesSrc);
  135. UserFreePool(pSrc);
  136. }
  137. return pDest;
  138. }
  139. /*
  140. * Allocation routines for rtl functions
  141. */
  142. PVOID UserRtlAllocMem(
  143. SIZE_T uBytes)
  144. {
  145. return UserAllocPool(uBytes, TAG_RTL);
  146. }
  147. VOID UserRtlFreeMem(
  148. PVOID pMem)
  149. {
  150. UserFreePool(pMem);
  151. }
  152. #ifdef POOL_INSTR
  153. VOID RecordStackTrace(
  154. VOID)
  155. {
  156. RtlZeroMemory(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
  157. RtlWalkFrameChain(gRecordedStackTrace, RECORD_STACK_TRACE_SIZE, 0);
  158. gpepRecorded = PsGetCurrentProcess();
  159. gpetRecorded = PsGetCurrentThread();
  160. }
  161. /***************************************************************************\
  162. * RecordFailAllocation
  163. *
  164. * Records failed allocations
  165. *
  166. * 3-22-99 CLupu Created.
  167. \***************************************************************************/
  168. VOID RecordFailAllocation(
  169. ULONG tag,
  170. SIZE_T size)
  171. {
  172. UserAssert(gdwPoolFlags & POOL_KEEP_FAIL_RECORD);
  173. gparrFailRecord[gdwFailRecordCrtIndex].ExtraData = LongToPtr( tag );
  174. gparrFailRecord[gdwFailRecordCrtIndex].size = size;
  175. gdwFailRecordTotalFailures++;
  176. RtlZeroMemory(gparrFailRecord[gdwFailRecordCrtIndex].trace,
  177. RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
  178. RtlWalkFrameChain(gparrFailRecord[gdwFailRecordCrtIndex].trace,
  179. RECORD_STACK_TRACE_SIZE,
  180. 0);
  181. gdwFailRecordCrtIndex++;
  182. if (gdwFailRecordCrtIndex >= gdwFailRecords) {
  183. gdwFailRecordCrtIndex = 0;
  184. }
  185. }
  186. /***************************************************************************\
  187. * RecordFreePool
  188. *
  189. * Records free pool
  190. *
  191. * 3-22-99 CLupu Created.
  192. \***************************************************************************/
  193. VOID RecordFreePool(
  194. PVOID p,
  195. SIZE_T size)
  196. {
  197. UserAssert(gdwPoolFlags & POOL_KEEP_FREE_RECORD);
  198. gparrFreeRecord[gdwFreeRecordCrtIndex].ExtraData = p;
  199. gparrFreeRecord[gdwFreeRecordCrtIndex].size = size;
  200. gdwFreeRecordTotalFrees++;
  201. RtlZeroMemory(gparrFreeRecord[gdwFreeRecordCrtIndex].trace,
  202. RECORD_STACK_TRACE_SIZE * sizeof(PVOID));
  203. RtlWalkFrameChain(gparrFreeRecord[gdwFreeRecordCrtIndex].trace,
  204. RECORD_STACK_TRACE_SIZE,
  205. 0);
  206. gdwFreeRecordCrtIndex++;
  207. if (gdwFreeRecordCrtIndex >= gdwFreeRecords) {
  208. gdwFreeRecordCrtIndex = 0;
  209. }
  210. }
  211. /***************************************************************************\
  212. * HeavyAllocPool
  213. *
  214. * This will make UserAllocPool to fail if we do not provide enough memory
  215. * for the specified tag.
  216. *
  217. * 12-02-96 CLupu Created.
  218. \***************************************************************************/
  219. PVOID HeavyAllocPool(
  220. SIZE_T uBytes,
  221. ULONG tag,
  222. DWORD dwFlags,
  223. EX_POOL_PRIORITY priority)
  224. {
  225. PDWORD p;
  226. PWin32PoolHead ph;
  227. POOL_TYPE poolType;
  228. if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) {
  229. if (dwFlags & DAP_USEQUOTA) {
  230. poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
  231. : gSessionPoolMask | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE);
  232. p = ExAllocatePoolWithQuotaTag(poolType, uBytes, tag);
  233. } else {
  234. poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool
  235. : gSessionPoolMask | PagedPool);
  236. if (dwFlags & DAP_PRIORITY) {
  237. p = ExAllocatePoolWithTagPriority(poolType, uBytes, tag, priority);
  238. } else {
  239. p = ExAllocatePoolWithTag(poolType, uBytes, tag);
  240. }
  241. }
  242. if (p != NULL && (dwFlags & DAP_ZEROINIT)) {
  243. RtlZeroMemory(p, uBytes);
  244. }
  245. return p;
  246. }
  247. /*
  248. * Check for overflow.
  249. */
  250. if (uBytes >= MAXULONG - sizeof(Win32PoolHead) - sizeof(gszTailAlloc)) {
  251. if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) {
  252. RecordFailAllocation(tag, 0);
  253. }
  254. return NULL;
  255. }
  256. /*
  257. * Acquire the mutex when we play with the list of allocations.
  258. */
  259. KeEnterCriticalRegion();
  260. ExAcquireFastMutexUnsafe(gpAllocFastMutex);
  261. #ifdef POOL_INSTR_API
  262. /*
  263. * Fail the allocation if the flag is set. Don't fail allocations that
  264. * will certainly get us to bugcheck in DBG (i.e. GLOBALTHREADLOCK).
  265. */
  266. if (gdwPoolFlags & POOL_FAIL_ALLOCS
  267. #if DBG
  268. && (tag != TAG_GLOBALTHREADLOCK)
  269. #endif
  270. ) {
  271. SIZE_T dwInd;
  272. for (dwInd = 0; dwInd < gdwTagsToFailCount; dwInd++) {
  273. if (tag == gparrTagsToFail[dwInd]) {
  274. break;
  275. }
  276. }
  277. if (dwInd < gdwTagsToFailCount) {
  278. if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) {
  279. RecordFailAllocation(tag, uBytes);
  280. }
  281. RIPMSG0(RIP_WARNING,
  282. "Pool allocation failed because of global restriction");
  283. p = NULL;
  284. goto exit;
  285. }
  286. }
  287. #endif
  288. #if DBG
  289. if ((gdwPoolFlags & POOL_FAIL_BY_INDEX) && (tag != TAG_GLOBALTHREADLOCK)) {
  290. /*
  291. * Count the calls to HeavyAllocPool.
  292. */
  293. gdwAllocCrt++;
  294. if (gdwAllocCrt >= gdwAllocFailIndex &&
  295. gdwAllocCrt < gdwAllocFailIndex + gdwAllocsToFail) {
  296. RecordStackTrace();
  297. KdPrint(("\n--------------------------------------------------\n"));
  298. KdPrint((
  299. "\nPool allocation %d failed because of registry settings",
  300. gdwAllocCrt));
  301. KdPrint(("\n--------------------------------------------------\n\n"));
  302. if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) {
  303. RecordFailAllocation(tag, uBytes);
  304. }
  305. p = NULL;
  306. goto exit;
  307. }
  308. }
  309. #endif
  310. /*
  311. * Reserve space for the header
  312. */
  313. uBytes += sizeof(Win32PoolHead);
  314. if (gdwPoolFlags & POOL_TAIL_CHECK) {
  315. uBytes += sizeof(gszTailAlloc);
  316. }
  317. if (dwFlags & DAP_USEQUOTA) {
  318. poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags) | NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
  319. : gSessionPoolMask | PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE);
  320. p = ExAllocatePoolWithQuotaTag(poolType, uBytes, tag);
  321. } else {
  322. poolType = ((dwFlags & DAP_NONPAGEDPOOL) ? USESESSION(dwFlags)| NonPagedPool
  323. : gSessionPoolMask | PagedPool);
  324. if (dwFlags & DAP_PRIORITY) {
  325. p = ExAllocatePoolWithTagPriority(poolType, uBytes, tag, priority);
  326. } else {
  327. p = ExAllocatePoolWithTag(poolType, uBytes, tag);
  328. }
  329. }
  330. /*
  331. * Return if ExAllocate... failed.
  332. */
  333. if (p == NULL) {
  334. if (gdwPoolFlags & POOL_KEEP_FAIL_RECORD) {
  335. uBytes -= sizeof(Win32PoolHead);
  336. if (gdwPoolFlags & POOL_TAIL_CHECK) {
  337. uBytes -= sizeof(gszTailAlloc);
  338. }
  339. RecordFailAllocation(tag, uBytes);
  340. }
  341. goto exit;
  342. }
  343. if (gdwPoolFlags & POOL_TAIL_CHECK) {
  344. uBytes -= sizeof(gszTailAlloc);
  345. RtlCopyMemory(((BYTE*)p) + uBytes, gszTailAlloc, sizeof(gszTailAlloc));
  346. }
  347. uBytes -= sizeof(Win32PoolHead);
  348. /*
  349. * Get the pointer to the header.
  350. */
  351. ph = (PWin32PoolHead)p;
  352. p += (sizeof(Win32PoolHead) / sizeof(DWORD));
  353. /*
  354. * Update the global allocations info.
  355. */
  356. gAllocList.dwCrtMem += uBytes;
  357. if (gAllocList.dwMaxMem < gAllocList.dwCrtMem) {
  358. gAllocList.dwMaxMem = gAllocList.dwCrtMem;
  359. }
  360. (gAllocList.dwCrtAlloc)++;
  361. if (gAllocList.dwMaxAlloc < gAllocList.dwCrtAlloc) {
  362. gAllocList.dwMaxAlloc = gAllocList.dwCrtAlloc;
  363. }
  364. /*
  365. * Grab the stack traces if the flags say so
  366. */
  367. if (gdwPoolFlags & POOL_CAPTURE_STACK) {
  368. ph->pTrace = ExAllocatePoolWithTag(gSessionPoolMask | PagedPool,
  369. POOL_ALLOC_TRACE_SIZE * sizeof(PVOID),
  370. TAG_STACK);
  371. if (ph->pTrace != NULL) {
  372. RtlZeroMemory(ph->pTrace, POOL_ALLOC_TRACE_SIZE * sizeof(PVOID));
  373. RtlWalkFrameChain(ph->pTrace, POOL_ALLOC_TRACE_SIZE, 0);
  374. }
  375. } else {
  376. ph->pTrace = NULL;
  377. }
  378. /*
  379. * Save the info in the header and return the pointer after the header.
  380. */
  381. ph->size = uBytes;
  382. /*
  383. * now, link it into the list for this tag (if any)
  384. */
  385. ph->pPrev = NULL;
  386. ph->pNext = gAllocList.pHead;
  387. if (gAllocList.pHead != NULL) {
  388. gAllocList.pHead->pPrev = ph;
  389. }
  390. gAllocList.pHead = ph;
  391. if (dwFlags & DAP_ZEROINIT) {
  392. RtlZeroMemory(p, uBytes);
  393. }
  394. exit:
  395. /*
  396. * Release the mutex
  397. */
  398. ExReleaseFastMutexUnsafe(gpAllocFastMutex);
  399. KeLeaveCriticalRegion();
  400. return p;
  401. }
  402. /***************************************************************************\
  403. * HeavyFreePool
  404. *
  405. * 12-02-96 CLupu Created.
  406. \***************************************************************************/
  407. VOID HeavyFreePool(
  408. PVOID p)
  409. {
  410. SIZE_T uBytes;
  411. PWin32PoolHead ph;
  412. /*
  413. * If POOL_HEAVY_ALLOCS is not defined
  414. * then the pointer is what we allocated
  415. */
  416. if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) {
  417. ExFreePool(p);
  418. return;
  419. }
  420. /*
  421. * Acquire the mutex when we play with the list of allocations
  422. */
  423. KeEnterCriticalRegion();
  424. ExAcquireFastMutexUnsafe(gpAllocFastMutex);
  425. ph = (PWin32PoolHead)((DWORD*)p - (sizeof(Win32PoolHead) / sizeof(DWORD)));
  426. uBytes = ph->size;
  427. /*
  428. * Check the tail
  429. */
  430. if (gdwPoolFlags & POOL_TAIL_CHECK) {
  431. if (!RtlEqualMemory((BYTE*)p + uBytes, gszTailAlloc, sizeof(gszTailAlloc))) {
  432. RIPMSG1(RIP_ERROR, "POOL CORRUPTION for %#p", p);
  433. }
  434. }
  435. gAllocList.dwCrtMem -= uBytes;
  436. UserAssert(gAllocList.dwCrtAlloc > 0);
  437. (gAllocList.dwCrtAlloc)--;
  438. /*
  439. * now, remove it from the linked list
  440. */
  441. if (ph->pPrev == NULL) {
  442. if (ph->pNext == NULL) {
  443. UserAssert(gAllocList.dwCrtAlloc == 0);
  444. gAllocList.pHead = NULL;
  445. } else {
  446. ph->pNext->pPrev = NULL;
  447. gAllocList.pHead = ph->pNext;
  448. }
  449. } else {
  450. ph->pPrev->pNext = ph->pNext;
  451. if (ph->pNext != NULL) {
  452. ph->pNext->pPrev = ph->pPrev;
  453. }
  454. }
  455. /*
  456. * Free the stack traces
  457. */
  458. if (ph->pTrace != NULL) {
  459. ExFreePool(ph->pTrace);
  460. }
  461. if (gdwPoolFlags & POOL_KEEP_FREE_RECORD) {
  462. RecordFreePool(ph, ph->size);
  463. }
  464. ExFreePool(ph);
  465. /*
  466. * Release the mutex
  467. */
  468. ExReleaseFastMutexUnsafe(gpAllocFastMutex);
  469. KeLeaveCriticalRegion();
  470. }
  471. /***************************************************************************\
  472. * CleanupPoolAllocations
  473. *
  474. * 12-02-96 CLupu Created.
  475. \***************************************************************************/
  476. VOID CleanupPoolAllocations(
  477. VOID)
  478. {
  479. PWin32PoolHead pHead;
  480. PWin32PoolHead pNext;
  481. if (gAllocList.dwCrtAlloc != 0) {
  482. if (gdwPoolFlags & POOL_BREAK_FOR_LEAKS) {
  483. FRE_RIPMSG0(RIP_ERROR,
  484. "There is still pool memory not freed in win32k.sys.\n"
  485. "Use !userkdx.dpa -vs to dump it");
  486. }
  487. pHead = gAllocList.pHead;
  488. while (pHead != NULL) {
  489. pNext = pHead->pNext;
  490. UserFreePool(pHead + 1);
  491. pHead = pNext;
  492. }
  493. }
  494. }
  495. /***************************************************************************\
  496. * CleanUpPoolLimitations
  497. *
  498. \***************************************************************************/
  499. VOID CleanUpPoolLimitations(
  500. VOID)
  501. {
  502. if (gpAllocFastMutex != NULL) {
  503. ExFreePool(gpAllocFastMutex);
  504. gpAllocFastMutex = NULL;
  505. }
  506. if (gparrFailRecord != NULL) {
  507. ExFreePool(gparrFailRecord);
  508. gparrFailRecord = NULL;
  509. }
  510. if (gparrFreeRecord != NULL) {
  511. ExFreePool(gparrFreeRecord);
  512. gparrFreeRecord = NULL;
  513. }
  514. if (gparrTagsToFail != NULL) {
  515. ExFreePool(gparrTagsToFail);
  516. gparrTagsToFail = NULL;
  517. }
  518. }
  519. /***************************************************************************\
  520. * InitPoolLimitations
  521. *
  522. * 12-02-96 CLupu Created.
  523. \***************************************************************************/
  524. NTSTATUS InitPoolLimitations(
  525. VOID)
  526. {
  527. UNICODE_STRING UnicodeString;
  528. OBJECT_ATTRIBUTES ObjectAttributes;
  529. HANDLE hkey;
  530. NTSTATUS Status;
  531. WCHAR achKeyValue[512];
  532. DWORD dwData;
  533. ULONG ucb;
  534. /*
  535. * Initialize a critical section structure that will be used to protect
  536. * all the HeavyAllocPool and HeavyFreePool calls.
  537. */
  538. gpAllocFastMutex = ExAllocatePoolWithTag(NonPagedPool,
  539. sizeof(FAST_MUTEX),
  540. TAG_DEBUG);
  541. if (gpAllocFastMutex == NULL) {
  542. RIPMSG0(RIP_WARNING, "InitPoolLimitations failed to allocate mutex");
  543. return STATUS_NO_MEMORY;
  544. }
  545. ExInitializeFastMutex(gpAllocFastMutex);
  546. /*
  547. * Allocate from session pool only for Full TS, that is Terminal Server
  548. * in app server mode. For normal Server (Remote Administration) or
  549. * workstation don't limit to session pool.
  550. */
  551. if ((SharedUserData->SuiteMask & VER_SUITE_TERMINAL) &&
  552. !(SharedUserData->SuiteMask & VER_SUITE_SINGLEUSERTS)) {
  553. gSessionPoolMask = SESSION_POOL_MASK;
  554. if (gbRemoteSession) {
  555. gdwPoolFlags |= POOL_HEAVY_ALLOCS;
  556. }
  557. } else {
  558. gSessionPoolMask = 0;
  559. }
  560. #if DBG
  561. gdwPoolFlags |= (POOL_HEAVY_ALLOCS | POOL_CAPTURE_STACK | POOL_BREAK_FOR_LEAKS);
  562. #endif
  563. /*
  564. * Open the key containing the limits.
  565. */
  566. RtlInitUnicodeString(
  567. &UnicodeString,
  568. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SubSystems\\Pool");
  569. InitializeObjectAttributes(
  570. &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
  571. Status = ZwOpenKey(&hkey, KEY_READ, &ObjectAttributes);
  572. if (!NT_SUCCESS(Status)) {
  573. #if DBG
  574. /*
  575. * More default settings if the Pool key doesn't exist
  576. */
  577. if (gbRemoteSession) {
  578. gparrFailRecord = ExAllocatePoolWithTag(PagedPool,
  579. 32 * sizeof(POOLRECORD),
  580. TAG_DEBUG);
  581. if (gparrFailRecord != NULL) {
  582. gdwFailRecords = 32;
  583. gdwPoolFlags |= POOL_KEEP_FAIL_RECORD;
  584. }
  585. gparrFreeRecord = ExAllocatePoolWithTag(PagedPool,
  586. 32 * sizeof(POOLRECORD),
  587. TAG_DEBUG);
  588. if (gparrFreeRecord != NULL) {
  589. gdwFreeRecords = 32;
  590. gdwPoolFlags |= POOL_KEEP_FREE_RECORD;
  591. }
  592. }
  593. #endif
  594. return STATUS_SUCCESS;
  595. }
  596. if (gbRemoteSession) {
  597. /*
  598. * Break in the debugger for memory leaks?
  599. */
  600. RtlInitUnicodeString(&UnicodeString, L"BreakForPoolLeaks");
  601. Status = ZwQueryValueKey(
  602. hkey,
  603. &UnicodeString,
  604. KeyValuePartialInformation,
  605. achKeyValue,
  606. sizeof(achKeyValue),
  607. &ucb);
  608. if (NT_SUCCESS(Status) &&
  609. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  610. dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  611. if (dwData != 0) {
  612. gdwPoolFlags |= POOL_BREAK_FOR_LEAKS;
  613. } else {
  614. gdwPoolFlags &= ~POOL_BREAK_FOR_LEAKS;
  615. }
  616. }
  617. /*
  618. * Heavy allocs/frees for remote sessions ?
  619. */
  620. RtlInitUnicodeString(&UnicodeString, L"HeavyRemoteSession");
  621. Status = ZwQueryValueKey(
  622. hkey,
  623. &UnicodeString,
  624. KeyValuePartialInformation,
  625. achKeyValue,
  626. sizeof(achKeyValue),
  627. &ucb);
  628. if (NT_SUCCESS(Status) &&
  629. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  630. dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  631. if (dwData == 0) {
  632. gdwPoolFlags &= ~POOL_HEAVY_ALLOCS;
  633. }
  634. }
  635. } else {
  636. /*
  637. * Heavy allocs/frees for main session ?
  638. */
  639. RtlInitUnicodeString(&UnicodeString, L"HeavyConsoleSession");
  640. Status = ZwQueryValueKey(
  641. hkey,
  642. &UnicodeString,
  643. KeyValuePartialInformation,
  644. achKeyValue,
  645. sizeof(achKeyValue),
  646. &ucb);
  647. if (NT_SUCCESS(Status) &&
  648. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  649. dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  650. if (dwData != 0) {
  651. gdwPoolFlags |= POOL_HEAVY_ALLOCS;
  652. }
  653. }
  654. }
  655. if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) {
  656. ZwClose(hkey);
  657. return STATUS_SUCCESS;
  658. }
  659. /*
  660. * Check for stack traces
  661. */
  662. RtlInitUnicodeString(&UnicodeString, L"StackTraces");
  663. Status = ZwQueryValueKey(
  664. hkey,
  665. &UnicodeString,
  666. KeyValuePartialInformation,
  667. achKeyValue,
  668. sizeof(achKeyValue),
  669. &ucb);
  670. if (NT_SUCCESS(Status) &&
  671. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  672. dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  673. if (dwData == 0) {
  674. gdwPoolFlags &= ~POOL_CAPTURE_STACK;
  675. } else {
  676. gdwPoolFlags |= POOL_CAPTURE_STACK;
  677. }
  678. }
  679. /*
  680. * Use tail checks ?
  681. */
  682. RtlInitUnicodeString(&UnicodeString, L"UseTailString");
  683. Status = ZwQueryValueKey(
  684. hkey,
  685. &UnicodeString,
  686. KeyValuePartialInformation,
  687. achKeyValue,
  688. sizeof(achKeyValue),
  689. &ucb);
  690. if (NT_SUCCESS(Status) &&
  691. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  692. dwData = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  693. if (dwData != 0) {
  694. gdwPoolFlags |= POOL_TAIL_CHECK;
  695. }
  696. }
  697. /*
  698. * Keep a record of frees ? By default keep the last 32.
  699. */
  700. #if DBG
  701. gdwFreeRecords = 32;
  702. #endif
  703. RtlInitUnicodeString(&UnicodeString, L"KeepFreeRecords");
  704. Status = ZwQueryValueKey(
  705. hkey,
  706. &UnicodeString,
  707. KeyValuePartialInformation,
  708. achKeyValue,
  709. sizeof(achKeyValue),
  710. &ucb);
  711. if (NT_SUCCESS(Status) &&
  712. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  713. gdwFreeRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  714. }
  715. if (gdwFreeRecords != 0) {
  716. gparrFreeRecord = ExAllocatePoolWithTag(PagedPool,
  717. gdwFreeRecords * sizeof(POOLRECORD),
  718. TAG_DEBUG);
  719. if (gparrFreeRecord != NULL) {
  720. gdwPoolFlags |= POOL_KEEP_FREE_RECORD;
  721. }
  722. }
  723. /*
  724. * Keep a record of failed allocations ? By default keep the last 32.
  725. */
  726. #if DBG
  727. gdwFailRecords = 32;
  728. #endif
  729. RtlInitUnicodeString(&UnicodeString, L"KeepFailRecords");
  730. Status = ZwQueryValueKey(
  731. hkey,
  732. &UnicodeString,
  733. KeyValuePartialInformation,
  734. achKeyValue,
  735. sizeof(achKeyValue),
  736. &ucb);
  737. if (NT_SUCCESS(Status) &&
  738. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  739. gdwFailRecords = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  740. }
  741. if (gdwFailRecords != 0) {
  742. gparrFailRecord = ExAllocatePoolWithTag(PagedPool,
  743. gdwFailRecords * sizeof(POOLRECORD),
  744. TAG_DEBUG);
  745. if (gparrFailRecord != NULL) {
  746. gdwPoolFlags |= POOL_KEEP_FAIL_RECORD;
  747. }
  748. }
  749. #if DBG
  750. /*
  751. * Open the key containing the allocation that should fail.
  752. */
  753. RtlInitUnicodeString(&UnicodeString, L"AllocationIndex");
  754. Status = ZwQueryValueKey(
  755. hkey,
  756. &UnicodeString,
  757. KeyValuePartialInformation,
  758. achKeyValue,
  759. sizeof(achKeyValue),
  760. &ucb);
  761. if (NT_SUCCESS(Status) &&
  762. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  763. gdwAllocFailIndex = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  764. }
  765. RtlInitUnicodeString(&UnicodeString, L"AllocationsToFail");
  766. Status = ZwQueryValueKey(
  767. hkey,
  768. &UnicodeString,
  769. KeyValuePartialInformation,
  770. achKeyValue,
  771. sizeof(achKeyValue),
  772. &ucb);
  773. if (NT_SUCCESS(Status) &&
  774. ((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Type == REG_DWORD) {
  775. gdwAllocsToFail = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)achKeyValue)->Data);
  776. }
  777. if (gdwAllocFailIndex != 0 && gdwAllocsToFail > 0) {
  778. gdwPoolFlags |= POOL_FAIL_BY_INDEX;
  779. }
  780. #endif
  781. ZwClose(hkey);
  782. return STATUS_SUCCESS;
  783. }
  784. #endif
  785. #ifdef POOL_INSTR_API
  786. BOOL _Win32PoolAllocationStats(
  787. LPDWORD parrTags,
  788. SIZE_T tagsCount,
  789. SIZE_T* lpdwMaxMem,
  790. SIZE_T* lpdwCrtMem,
  791. LPDWORD lpdwMaxAlloc,
  792. LPDWORD lpdwCrtAlloc)
  793. {
  794. BOOL bRet = FALSE;
  795. /*
  796. * Do nothing if heavy allocs/frees are disabled.
  797. */
  798. if (!(gdwPoolFlags & POOL_HEAVY_ALLOCS)) {
  799. return FALSE;
  800. }
  801. *lpdwMaxMem = gAllocList.dwMaxMem;
  802. *lpdwCrtMem = gAllocList.dwCrtMem;
  803. *lpdwMaxAlloc = gAllocList.dwMaxAlloc;
  804. *lpdwCrtAlloc = gAllocList.dwCrtAlloc;
  805. /*
  806. * Acquire the mutex when we play with the list of allocations.
  807. */
  808. KeEnterCriticalRegion();
  809. ExAcquireFastMutexUnsafe(gpAllocFastMutex);
  810. if (gparrTagsToFail != NULL) {
  811. ExFreePool(gparrTagsToFail);
  812. gparrTagsToFail = NULL;
  813. gdwTagsToFailCount = 0;
  814. }
  815. if (tagsCount != 0) {
  816. gdwPoolFlags |= POOL_FAIL_ALLOCS;
  817. if (tagsCount > MAX_TAGS_TO_FAIL) {
  818. gdwTagsToFailCount = 0xFFFFFFFF;
  819. RIPMSG0(RIP_WARNING, "All pool allocations in WIN32K.SYS will fail.");
  820. bRet = TRUE;
  821. goto exit;
  822. }
  823. } else {
  824. gdwPoolFlags &= ~POOL_FAIL_ALLOCS;
  825. RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal.");
  826. bRet = TRUE;
  827. goto exit;
  828. }
  829. gparrTagsToFail = ExAllocatePoolWithTag(PagedPool,
  830. sizeof(DWORD) * tagsCount,
  831. TAG_DEBUG);
  832. if (gparrTagsToFail == NULL) {
  833. gdwPoolFlags &= ~POOL_FAIL_ALLOCS;
  834. RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal !");
  835. goto exit;
  836. }
  837. try {
  838. ProbeForRead(parrTags, sizeof(DWORD) * tagsCount, DATAALIGN);
  839. RtlCopyMemory(gparrTagsToFail, parrTags, sizeof(DWORD) * tagsCount);
  840. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  841. if (gparrTagsToFail != NULL) {
  842. ExFreePool(gparrTagsToFail);
  843. gparrTagsToFail = NULL;
  844. gdwPoolFlags &= ~POOL_FAIL_ALLOCS;
  845. RIPMSG0(RIP_WARNING, "Pool allocations in WIN32K.SYS back to normal.");
  846. goto exit;
  847. }
  848. }
  849. gdwTagsToFailCount = tagsCount;
  850. RIPMSG0(RIP_WARNING, "Specific pool allocations in WIN32K.SYS will fail.");
  851. exit:
  852. /*
  853. * Release the mutex
  854. */
  855. ExReleaseFastMutexUnsafe(gpAllocFastMutex);
  856. KeLeaveCriticalRegion();
  857. return bRet;
  858. }
  859. #endif
  860. #ifdef TRACE_MAP_VIEWS
  861. FAST_MUTEX* gpSectionFastMutex;
  862. PWin32Section gpSections;
  863. #define EnterSectionCrit() \
  864. KeEnterCriticalRegion(); \
  865. ExAcquireFastMutexUnsafe(gpSectionFastMutex);
  866. #define LeaveSectionCrit() \
  867. ExReleaseFastMutexUnsafe(gpSectionFastMutex); \
  868. KeLeaveCriticalRegion();
  869. /***************************************************************************\
  870. * CleanUpSections
  871. *
  872. \***************************************************************************/
  873. VOID CleanUpSections(
  874. VOID)
  875. {
  876. if (gpSectionFastMutex) {
  877. ExFreePool(gpSectionFastMutex);
  878. gpSectionFastMutex = NULL;
  879. }
  880. }
  881. NTSTATUS InitSectionTrace(
  882. VOID)
  883. {
  884. gpSectionFastMutex = ExAllocatePoolWithTag(NonPagedPool,
  885. sizeof(FAST_MUTEX),
  886. TAG_DEBUG);
  887. if (gpSectionFastMutex == NULL) {
  888. RIPMSG0(RIP_WARNING, "InitSectionTrace failed to allocate mutex");
  889. return STATUS_NO_MEMORY;
  890. }
  891. ExInitializeFastMutex(gpSectionFastMutex);
  892. return STATUS_SUCCESS;
  893. }
  894. NTSTATUS _Win32CreateSection(
  895. PVOID* pSectionObject,
  896. ACCESS_MASK DesiredAccess,
  897. POBJECT_ATTRIBUTES ObjectAttributes,
  898. PLARGE_INTEGER pInputMaximumSize,
  899. ULONG SectionPageProtection,
  900. ULONG AllocationAttributes,
  901. HANDLE FileHandle,
  902. PFILE_OBJECT FileObject,
  903. DWORD SectionTag)
  904. {
  905. PWin32Section pSection;
  906. NTSTATUS Status;
  907. Status = MmCreateSection(
  908. pSectionObject,
  909. DesiredAccess,
  910. ObjectAttributes,
  911. pInputMaximumSize,
  912. SectionPageProtection,
  913. AllocationAttributes,
  914. FileHandle,
  915. FileObject);
  916. if (NT_SUCCESS(Status)) {
  917. ObDeleteCapturedInsertInfo(*pSectionObject);
  918. } else {
  919. RIPMSG1(RIP_WARNING, "MmCreateSection failed with Status 0x%x.", Status);
  920. *pSectionObject = NULL;
  921. return Status;
  922. }
  923. pSection = UserAllocPoolZInit(sizeof(Win32Section), TAG_SECTION);
  924. if (pSection == NULL) {
  925. ObDereferenceObject(*pSectionObject);
  926. RIPMSG0(RIP_WARNING, "Failed to allocate memory for section.");
  927. *pSectionObject = NULL;
  928. return STATUS_UNSUCCESSFUL;
  929. }
  930. EnterSectionCrit();
  931. pSection->pNext = gpSections;
  932. if (gpSections != NULL) {
  933. UserAssert(gpSections->pPrev == NULL);
  934. gpSections->pPrev = pSection;
  935. }
  936. pSection->SectionObject = *pSectionObject;
  937. pSection->SectionSize = *pInputMaximumSize;
  938. pSection->SectionTag = SectionTag;
  939. gpSections = pSection;
  940. #ifdef MAP_VIEW_STACK_TRACE
  941. RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
  942. RtlWalkFrameChain(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
  943. #endif
  944. LeaveSectionCrit();
  945. return STATUS_SUCCESS;
  946. }
  947. NTSTATUS _ZwWin32CreateSection(
  948. PVOID* pSectionObject,
  949. ACCESS_MASK DesiredAccess,
  950. POBJECT_ATTRIBUTES ObjectAttributes,
  951. PLARGE_INTEGER pInputMaximumSize,
  952. ULONG SectionPageProtection,
  953. ULONG AllocationAttributes,
  954. HANDLE FileHandle,
  955. PFILE_OBJECT FileObject,
  956. DWORD SectionTag)
  957. {
  958. PWin32Section pSection;
  959. NTSTATUS Status;
  960. HANDLE SectionHandle;
  961. UNREFERENCED_PARAMETER(FileObject);
  962. Status = ZwCreateSection(
  963. &SectionHandle,
  964. DesiredAccess,
  965. ObjectAttributes,
  966. pInputMaximumSize,
  967. SectionPageProtection,
  968. AllocationAttributes,
  969. FileHandle);
  970. if (!NT_SUCCESS(Status)) {
  971. RIPMSG1(RIP_WARNING, "ZwCreateSection failed with Statu %x", Status);
  972. *pSectionObject = NULL;
  973. return Status;
  974. }
  975. Status = ObReferenceObjectByHandle(
  976. SectionHandle,
  977. DesiredAccess,
  978. *(POBJECT_TYPE *)MmSectionObjectType,
  979. KernelMode,
  980. pSectionObject,
  981. NULL);
  982. ZwClose(SectionHandle);
  983. if (!NT_SUCCESS(Status)) {
  984. RIPMSG1(RIP_WARNING,
  985. "ObReferenceObjectByHandle failed with Status 0x%x",
  986. Status);
  987. *pSectionObject = NULL;
  988. return Status;
  989. }
  990. pSection = UserAllocPoolZInit(sizeof(Win32Section), TAG_SECTION);
  991. if (pSection == NULL) {
  992. ObDereferenceObject(*pSectionObject);
  993. RIPMSG0(RIP_WARNING, "Failed to allocate memory for section");
  994. *pSectionObject = NULL;
  995. return STATUS_UNSUCCESSFUL;
  996. }
  997. EnterSectionCrit();
  998. pSection->pNext = gpSections;
  999. if (gpSections != NULL) {
  1000. UserAssert(gpSections->pPrev == NULL);
  1001. gpSections->pPrev = pSection;
  1002. }
  1003. pSection->SectionObject = *pSectionObject;
  1004. pSection->SectionSize = *pInputMaximumSize;
  1005. pSection->SectionTag = SectionTag;
  1006. gpSections = pSection;
  1007. #ifdef MAP_VIEW_STACK_TRACE
  1008. RtlZeroMemory(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
  1009. RtlWalkFrameChain(pSection->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
  1010. #endif
  1011. LeaveSectionCrit();
  1012. return STATUS_SUCCESS;
  1013. }
  1014. VOID _Win32DestroySection(
  1015. PVOID Section)
  1016. {
  1017. PWin32Section ps;
  1018. EnterSectionCrit();
  1019. ps = gpSections;
  1020. while (ps != NULL) {
  1021. if (ps->SectionObject == Section) {
  1022. /*
  1023. * Make sure there is no view mapped for this section
  1024. */
  1025. if (ps->pFirstView != NULL) {
  1026. RIPMSG1(RIP_ERROR, "Section %#p still has views", ps);
  1027. }
  1028. /*
  1029. * now, remove it from the linked list of this tag
  1030. */
  1031. if (ps->pPrev == NULL) {
  1032. UserAssert(ps == gpSections);
  1033. gpSections = ps->pNext;
  1034. if (ps->pNext != NULL) {
  1035. ps->pNext->pPrev = NULL;
  1036. }
  1037. } else {
  1038. ps->pPrev->pNext = ps->pNext;
  1039. if (ps->pNext != NULL) {
  1040. ps->pNext->pPrev = ps->pPrev;
  1041. }
  1042. }
  1043. ObDereferenceObject(Section);
  1044. UserFreePool(ps);
  1045. LeaveSectionCrit();
  1046. return;
  1047. }
  1048. ps = ps->pNext;
  1049. }
  1050. RIPMSG1(RIP_ERROR, "Cannot find Section %#p", Section);
  1051. LeaveSectionCrit();
  1052. }
  1053. NTSTATUS _Win32MapViewInSessionSpace(
  1054. PVOID Section,
  1055. PVOID* pMappedBase,
  1056. PSIZE_T pViewSize)
  1057. {
  1058. NTSTATUS Status;
  1059. PWin32Section ps;
  1060. PWin32MapView pMapView;
  1061. /*
  1062. * First try to map the view
  1063. */
  1064. Status = MmMapViewInSessionSpace(Section, pMappedBase, pViewSize);
  1065. if (!NT_SUCCESS(Status)) {
  1066. RIPMSG1(RIP_WARNING, "MmMapViewInSessionSpace failed with Status %x",
  1067. Status);
  1068. *pMappedBase = NULL;
  1069. return Status;
  1070. }
  1071. /*
  1072. * Now add a record for this view
  1073. */
  1074. pMapView = UserAllocPoolZInit(sizeof(Win32MapView), TAG_SECTION);
  1075. if (pMapView == NULL) {
  1076. RIPMSG0(RIP_WARNING, "_Win32MapViewInSessionSpace: Memory failure");
  1077. MmUnmapViewInSessionSpace(*pMappedBase);
  1078. *pMappedBase = NULL;
  1079. return STATUS_NO_MEMORY;
  1080. }
  1081. pMapView->pViewBase = *pMappedBase;
  1082. pMapView->ViewSize = *pViewSize;
  1083. EnterSectionCrit();
  1084. ps = gpSections;
  1085. while (ps != NULL) {
  1086. if (ps->SectionObject == Section) {
  1087. pMapView->pSection = ps;
  1088. pMapView->pNext = ps->pFirstView;
  1089. if (ps->pFirstView != NULL) {
  1090. ps->pFirstView->pPrev = pMapView;
  1091. }
  1092. ps->pFirstView = pMapView;
  1093. #ifdef MAP_VIEW_STACK_TRACE
  1094. RtlZeroMemory(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE * sizeof(PVOID));
  1095. RtlWalkFrameChain(pMapView->trace, MAP_VIEW_STACK_TRACE_SIZE, 0);
  1096. #endif
  1097. LeaveSectionCrit();
  1098. return STATUS_SUCCESS;
  1099. }
  1100. ps = ps->pNext;
  1101. }
  1102. RIPMSG1(RIP_ERROR, "_Win32MapViewInSessionSpace: Could not find section for %#p",
  1103. Section);
  1104. LeaveSectionCrit();
  1105. return STATUS_UNSUCCESSFUL;
  1106. }
  1107. NTSTATUS _Win32UnmapViewInSessionSpace(
  1108. PVOID MappedBase)
  1109. {
  1110. PWin32Section ps;
  1111. PWin32MapView pv;
  1112. NTSTATUS Status;
  1113. EnterSectionCrit();
  1114. ps = gpSections;
  1115. while (ps != NULL) {
  1116. pv = ps->pFirstView;
  1117. while (pv != NULL) {
  1118. UserAssert(pv->pSection == ps);
  1119. if (pv->pViewBase == MappedBase) {
  1120. /*
  1121. * now, remove it from the linked list
  1122. */
  1123. if (pv->pPrev == NULL) {
  1124. UserAssert(pv == ps->pFirstView);
  1125. ps->pFirstView = pv->pNext;
  1126. if (pv->pNext != NULL) {
  1127. pv->pNext->pPrev = NULL;
  1128. }
  1129. } else {
  1130. pv->pPrev->pNext = pv->pNext;
  1131. if (pv->pNext != NULL) {
  1132. pv->pNext->pPrev = pv->pPrev;
  1133. }
  1134. }
  1135. UserFreePool(pv);
  1136. Status = MmUnmapViewInSessionSpace(MappedBase);
  1137. LeaveSectionCrit();
  1138. return Status;
  1139. }
  1140. pv = pv->pNext;
  1141. }
  1142. ps = ps->pNext;
  1143. }
  1144. RIPMSG1(RIP_ERROR,
  1145. "_Win32UnmapViewInSessionSpace: Could not find view for 0x%p",
  1146. MappedBase);
  1147. LeaveSectionCrit();
  1148. return STATUS_UNSUCCESSFUL;
  1149. }
  1150. #endif