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.

1718 lines
45 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. support.c
  5. Abstract:
  6. This module implements internal support routines
  7. for the verification code.
  8. Author:
  9. Silviu Calinoiu (SilviuC) 1-Mar-2001
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #include "verifier.h"
  14. #include "support.h"
  15. #include "critsect.h"
  16. #include "vspace.h"
  17. #include "logging.h"
  18. #include "tracker.h"
  19. //
  20. // Global data.
  21. //
  22. SYSTEM_BASIC_INFORMATION AVrfpSysBasicInfo;
  23. //
  24. // Global counters (for statistics).
  25. //
  26. ULONG AVrfpCounter[CNT_MAXIMUM_INDEX];
  27. //
  28. // Break triggers.
  29. //
  30. ULONG AVrfpBreak [BRK_MAXIMUM_INDEX];
  31. /////////////////////////////////////////////////////////////////////
  32. ////////////////////////////////// Private ntdll entrypoints pointers
  33. /////////////////////////////////////////////////////////////////////
  34. PFN_RTLP_DEBUG_PAGE_HEAP_CREATE AVrfpRtlpDebugPageHeapCreate;
  35. PFN_RTLP_DEBUG_PAGE_HEAP_DESTROY AVrfpRtlpDebugPageHeapDestroy;
  36. PFN_RTLP_GET_STACK_TRACE_ADDRESS AVrfpGetStackTraceAddress;
  37. //
  38. // Exception logging support.
  39. //
  40. PAVRF_EXCEPTION_LOG_ENTRY AVrfpExceptionLog = NULL;
  41. const ULONG AVrfpExceptionLogEntriesNo = 128;
  42. LONG AVrfpExceptionLogCurrentIndex = 0;
  43. PVOID AVrfpVectoredExceptionPointer;
  44. //
  45. // Internal functions declarations
  46. //
  47. LONG
  48. NTAPI
  49. AVrfpVectoredExceptionHandler (
  50. struct _EXCEPTION_POINTERS * ExceptionPointers
  51. );
  52. VOID
  53. AVrfpCheckFirstChanceException (
  54. struct _EXCEPTION_POINTERS * ExceptionPointers
  55. );
  56. VOID
  57. AVrfpInitializeExceptionChecking (
  58. VOID
  59. )
  60. {
  61. PVOID Handler;
  62. //
  63. // Establish a first chance exception handler.
  64. //
  65. Handler = RtlAddVectoredExceptionHandler (1, AVrfpVectoredExceptionHandler);
  66. AVrfpVectoredExceptionPointer = Handler;
  67. //
  68. // Allocate memory for our exception logging database.
  69. // If the allocation fails we will simply continue execution
  70. // with this feature disabled.
  71. //
  72. ASSERT (AVrfpExceptionLog == NULL);
  73. AVrfpExceptionLog = (PAVRF_EXCEPTION_LOG_ENTRY)
  74. AVrfpAllocate (AVrfpExceptionLogEntriesNo * sizeof (AVRF_EXCEPTION_LOG_ENTRY));
  75. }
  76. VOID
  77. AVrfpCleanupExceptionChecking (
  78. VOID
  79. )
  80. {
  81. //
  82. // Establish a first chance exception handler.
  83. //
  84. if (AVrfpVectoredExceptionPointer) {
  85. RtlRemoveVectoredExceptionHandler (AVrfpVectoredExceptionPointer);
  86. }
  87. //
  88. // Free exception log database.
  89. //
  90. if (AVrfpExceptionLog) {
  91. AVrfpFree (AVrfpExceptionLog);
  92. AVrfpExceptionLog = NULL;
  93. }
  94. }
  95. VOID
  96. AVrfpLogException (
  97. struct _EXCEPTION_POINTERS * ExceptionPointers
  98. )
  99. {
  100. ULONG NewIndex;
  101. if (AVrfpExceptionLog != NULL) {
  102. NewIndex = (ULONG)InterlockedIncrement (&AVrfpExceptionLogCurrentIndex) % AVrfpExceptionLogEntriesNo;
  103. AVrfpExceptionLog[NewIndex].ThreadId = NtCurrentTeb()->ClientId.UniqueThread;
  104. AVrfpExceptionLog[NewIndex].ExceptionCode = ExceptionPointers->ExceptionRecord->ExceptionCode;
  105. AVrfpExceptionLog[NewIndex].ExceptionAddress = ExceptionPointers->ExceptionRecord->ExceptionAddress;
  106. AVrfpExceptionLog[NewIndex].ExceptionRecord = ExceptionPointers->ExceptionRecord;
  107. AVrfpExceptionLog[NewIndex].ContextRecord = ExceptionPointers->ContextRecord;
  108. }
  109. }
  110. LONG
  111. NTAPI
  112. AVrfpVectoredExceptionHandler (
  113. struct _EXCEPTION_POINTERS * ExceptionPointers
  114. )
  115. {
  116. DWORD ExceptionCode;
  117. //
  118. // We are holding RtlpCalloutEntryLock at this point
  119. // so we are trying to protect ourselves with this other
  120. // try...except against possible other exceptions
  121. // (e.g. an inpage error) that could leave the lock orphaned.
  122. //
  123. try {
  124. AVrfpLogException (ExceptionPointers);
  125. AVrfpCheckFirstChanceException (ExceptionPointers);
  126. ExceptionCode = ExceptionPointers->ExceptionRecord->ExceptionCode;
  127. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_EXCEPTIONS) != 0) {
  128. DbgPrint ("AVRF: Exception %x from address %p\n",
  129. ExceptionCode,
  130. ExceptionPointers->ExceptionRecord->ExceptionAddress);
  131. }
  132. if (ExceptionCode == STATUS_INVALID_HANDLE) {
  133. //
  134. // RPC is using STATUS_INVALID_HANDLE exceptions with EXCEPTION_NONCONTINUABLE
  135. // for a private notification mechanism. The exceptions we are looking for
  136. // are coming from the kernel code and they don't have the EXCEPTION_NONCONTINUABLE
  137. // flag set.
  138. //
  139. if ((ExceptionPointers->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == 0) {
  140. //
  141. // Note. When run under debugger this message will not kick in when an
  142. // exception gets raised because the debugger will break on first chance
  143. // exception. Only if the debugger is launched with `-xd ch' (ignore
  144. // first chance invalid handle exception) the message will be seen first.
  145. // Otherwise you see a plain exception and only after you hit go in
  146. // the debugger console you get the message.
  147. //
  148. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_HANDLE | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  149. "invalid handle exception for current stack trace",
  150. ExceptionCode, "Exception code.",
  151. ExceptionPointers->ExceptionRecord, "Exception record. Use .exr to display it.",
  152. ExceptionPointers->ContextRecord, "Context record. Use .cxr to display it.",
  153. 0, "");
  154. //
  155. // We are hiding this exception after the verifier stop so the callers
  156. // of APIs like SetEvent with an invalid handle will not see the exception.
  157. //
  158. return EXCEPTION_CONTINUE_EXECUTION;
  159. }
  160. }
  161. }
  162. except (EXCEPTION_EXECUTE_HANDLER) {
  163. // NOTHING;
  164. }
  165. return EXCEPTION_CONTINUE_SEARCH;
  166. }
  167. VOID
  168. AVrfpDirtyThreadStack (
  169. VOID
  170. )
  171. {
  172. PTEB Teb = NtCurrentTeb();
  173. ULONG_PTR StackStart;
  174. ULONG_PTR StackEnd;
  175. try {
  176. StackStart = (ULONG_PTR)(Teb->NtTib.StackLimit);
  177. //
  178. // We dirty stacks only on x86 architectures.
  179. //
  180. #if defined(_X86_)
  181. _asm mov StackEnd, ESP;
  182. #else
  183. StackEnd = StackStart;
  184. #endif
  185. //
  186. // Limit stack dirtying to only 8K.
  187. //
  188. if (StackStart < StackEnd - 0x2000) {
  189. StackStart = StackEnd - 0x2000;
  190. }
  191. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DIRTY_STACKS) != 0) {
  192. DbgPrint ("Dirtying stack range %p - %p for thread %p \n",
  193. StackStart, StackEnd, Teb->ClientId.UniqueThread);
  194. }
  195. while (StackStart < StackEnd) {
  196. *((PULONG)StackStart) = 0xBAD1BAD1;
  197. StackStart += sizeof(ULONG);
  198. }
  199. }
  200. except (EXCEPTION_EXECUTE_HANDLER) {
  201. // nothing
  202. }
  203. }
  204. /////////////////////////////////////////////////////////////////////
  205. //////////////////////////////////////////////////// Per thread table
  206. /////////////////////////////////////////////////////////////////////
  207. #define THREAD_TABLE_SIZE 61
  208. LIST_ENTRY AVrfpThreadTable [THREAD_TABLE_SIZE];
  209. RTL_CRITICAL_SECTION AVrfpThreadTableLock;
  210. //
  211. // Keep this constant so the debugger can read it.
  212. //
  213. const ULONG AVrfpThreadTableEntriesNo = THREAD_TABLE_SIZE;
  214. //
  215. // Keep this for debugging purposes.
  216. //
  217. AVRF_THREAD_ENTRY AVrfpMostRecentRemovedThreadEntry;
  218. NTSTATUS
  219. AVrfpThreadTableInitialize (
  220. VOID
  221. )
  222. {
  223. PAVRF_THREAD_ENTRY Entry;
  224. ULONG I;
  225. NTSTATUS Status;
  226. Status = RtlInitializeCriticalSection (&AVrfpThreadTableLock);
  227. if (!NT_SUCCESS(Status)) {
  228. return Status;
  229. }
  230. for (I = 0; I < THREAD_TABLE_SIZE; I += 1) {
  231. InitializeListHead (&(AVrfpThreadTable[I]));
  232. }
  233. //
  234. // Create an entry for the current thread (main thread). The function
  235. // is called during verifier!DllMain when there is a single thread
  236. // running in the process.
  237. //
  238. Entry = AVrfpAllocate (sizeof *Entry);
  239. if (Entry == NULL) {
  240. return STATUS_NO_MEMORY;
  241. }
  242. Entry->Id = NtCurrentTeb()->ClientId.UniqueThread;
  243. AVrfpThreadTableAddEntry (Entry);
  244. return STATUS_SUCCESS;
  245. }
  246. VOID
  247. AVrfpThreadTableAddEntry (
  248. PAVRF_THREAD_ENTRY Entry
  249. )
  250. {
  251. ULONG ChainIndex;
  252. ASSERT (Entry != NULL);
  253. ASSERT (Entry->Id != NULL);
  254. ChainIndex = (HandleToUlong(Entry->Id) >> 2) % THREAD_TABLE_SIZE;
  255. RtlEnterCriticalSection (&AVrfpThreadTableLock);
  256. //
  257. // It is important to add the new entry at the head of the list
  258. // (not tail) because the list can contain zombies left after someone
  259. // called TerminateThread and the thread handle value got reused.
  260. //
  261. InsertHeadList (&(AVrfpThreadTable[ChainIndex]),
  262. &(Entry->HashChain));
  263. RtlLeaveCriticalSection (&AVrfpThreadTableLock);
  264. }
  265. VOID
  266. AVrfpThreadTableRemoveEntry (
  267. PAVRF_THREAD_ENTRY Entry
  268. )
  269. {
  270. RtlEnterCriticalSection (&AVrfpThreadTableLock);
  271. RtlCopyMemory (&AVrfpMostRecentRemovedThreadEntry,
  272. Entry,
  273. sizeof (AVrfpMostRecentRemovedThreadEntry));
  274. RemoveEntryList (&(Entry->HashChain));
  275. RtlLeaveCriticalSection (&AVrfpThreadTableLock);
  276. }
  277. PAVRF_THREAD_ENTRY
  278. AVrfpThreadTableSearchEntry (
  279. HANDLE Id
  280. )
  281. {
  282. ULONG ChainIndex;
  283. PLIST_ENTRY Current;
  284. PAVRF_THREAD_ENTRY Entry;
  285. PAVRF_THREAD_ENTRY Result;
  286. ChainIndex = (HandleToUlong(Id) >> 2) % THREAD_TABLE_SIZE;
  287. Result = NULL;
  288. RtlEnterCriticalSection (&AVrfpThreadTableLock);
  289. Current = AVrfpThreadTable[ChainIndex].Flink;
  290. while (Current != &(AVrfpThreadTable[ChainIndex])) {
  291. Entry = CONTAINING_RECORD (Current,
  292. AVRF_THREAD_ENTRY,
  293. HashChain);
  294. if (Entry->Id == Id) {
  295. Result = Entry;
  296. goto Exit;
  297. }
  298. Current = Current->Flink;
  299. }
  300. Exit:
  301. RtlLeaveCriticalSection (&AVrfpThreadTableLock);
  302. return Result;
  303. }
  304. /////////////////////////////////////////////////////////////////////
  305. /////////////////////////////////////////////////// Verifier TLS slot
  306. /////////////////////////////////////////////////////////////////////
  307. #define INVALID_TLS_INDEX 0xFFFFFFFF
  308. ULONG AVrfpTlsIndex = INVALID_TLS_INDEX;
  309. AVRF_TLS_STRUCT AVrfpFirstThreadTlsStruct = { 0 };
  310. LIST_ENTRY AVrfpTlsListHead;
  311. NTSTATUS
  312. AVrfpAllocateVerifierTlsSlot (
  313. VOID
  314. )
  315. {
  316. PPEB Peb;
  317. PTEB Teb;
  318. DWORD Index;
  319. NTSTATUS Status;
  320. InitializeListHead (&AVrfpTlsListHead);
  321. Peb = NtCurrentPeb();
  322. Teb = NtCurrentTeb();
  323. Status = STATUS_SUCCESS;
  324. RtlAcquirePebLock();
  325. //
  326. // This function is called very early during process startup therefore
  327. // we expect to find a TLS index in the first slots (most typically
  328. // it is zero although we do not do anything specific to enforce that).
  329. //
  330. Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
  331. if (Index == INVALID_TLS_INDEX) {
  332. DbgPrint ("AVRF: failed to allocated a verifier TLS slot.\n");
  333. Status = STATUS_UNSUCCESSFUL;
  334. goto Exit;
  335. }
  336. AVrfpTlsIndex = Index;
  337. AVrfpFirstThreadTlsStruct.Teb = Teb;
  338. AVrfpFirstThreadTlsStruct.ThreadId = Teb->ClientId.UniqueThread;
  339. InsertHeadList (&AVrfpTlsListHead,
  340. &AVrfpFirstThreadTlsStruct.ListEntry);
  341. Teb->TlsSlots[Index] = &AVrfpFirstThreadTlsStruct;
  342. Exit:
  343. RtlReleasePebLock();
  344. return Status;
  345. }
  346. PAVRF_TLS_STRUCT
  347. AVrfpGetVerifierTlsValue(
  348. VOID
  349. )
  350. {
  351. PTEB Teb;
  352. PVOID *Slot;
  353. if (AVrfpTlsIndex == INVALID_TLS_INDEX) {
  354. return NULL;
  355. }
  356. Teb = NtCurrentTeb();
  357. Slot = &Teb->TlsSlots[AVrfpTlsIndex];
  358. return (PAVRF_TLS_STRUCT)*Slot;
  359. }
  360. VOID
  361. AVrfpSetVerifierTlsValue(
  362. PAVRF_TLS_STRUCT Value
  363. )
  364. {
  365. PTEB Teb;
  366. if (AVrfpTlsIndex == INVALID_TLS_INDEX) {
  367. return;
  368. }
  369. Teb = NtCurrentTeb();
  370. Teb->TlsSlots[AVrfpTlsIndex] = Value;
  371. }
  372. VOID
  373. AvrfpThreadAttach (
  374. VOID
  375. )
  376. {
  377. PAVRF_TLS_STRUCT TlsStruct;
  378. PTEB Teb;
  379. ASSERT (AVrfpGetVerifierTlsValue () == NULL);
  380. TlsStruct = (PAVRF_TLS_STRUCT) AVrfpAllocate (sizeof *TlsStruct);
  381. if (TlsStruct != NULL) {
  382. Teb = NtCurrentTeb();
  383. TlsStruct->ThreadId = Teb->ClientId.UniqueThread;
  384. TlsStruct->Teb = Teb;
  385. //
  386. // We are protected by the loader lock so we shouldn't
  387. // need any additional synchronization here.
  388. //
  389. InsertHeadList (&AVrfpTlsListHead,
  390. &TlsStruct->ListEntry);
  391. AVrfpSetVerifierTlsValue (TlsStruct);
  392. }
  393. }
  394. VOID
  395. AvrfpThreadDetach (
  396. VOID
  397. )
  398. {
  399. volatile PAVRF_TLS_STRUCT TlsStruct;
  400. PTEB Teb;
  401. TlsStruct = AVrfpGetVerifierTlsValue();
  402. if (TlsStruct != NULL && TlsStruct != &AVrfpFirstThreadTlsStruct) {
  403. //
  404. // We are protected by the loader lock so we shouldn't
  405. // need any additional synchronization here.
  406. //
  407. Teb = NtCurrentTeb();
  408. if (TlsStruct->Teb != Teb || TlsStruct->ThreadId != Teb->ClientId.UniqueThread) {
  409. VERIFIER_STOP (APPLICATION_VERIFIER_INTERNAL_ERROR,
  410. "Corrupted TLS structure",
  411. TlsStruct->Teb, "TEB address",
  412. Teb, "Expected TEB address",
  413. TlsStruct->ThreadId, "Thread ID",
  414. Teb->ClientId.UniqueThread, "Expected Thread ID");
  415. }
  416. RemoveEntryList (&TlsStruct->ListEntry);
  417. AVrfpFree (TlsStruct);
  418. AVrfpSetVerifierTlsValue (NULL);
  419. }
  420. //
  421. // Delete the virtual space region containing the thread's stack from
  422. // the tracked. Since the stack is freed from kernel mode we will miss
  423. // the operation otherwise.
  424. //
  425. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING) != 0) {
  426. AVrfpVsTrackDeleteRegionContainingAddress (&TlsStruct);
  427. }
  428. }
  429. /////////////////////////////////////////////////////////////////////
  430. ///////////////////////////////////////////// Dll entry point hooking
  431. /////////////////////////////////////////////////////////////////////
  432. typedef struct _DLL_ENTRY_POINT_INFO {
  433. LIST_ENTRY List;
  434. PVOID DllBase;
  435. PDLL_INIT_ROUTINE EntryPoint;
  436. PLDR_DATA_TABLE_ENTRY Ldr;
  437. } DLL_ENTRY_POINT_INFO, * PDLL_ENTRY_POINT_INFO;
  438. LIST_ENTRY DllLoadListHead;
  439. RTL_CRITICAL_SECTION DllLoadListLock;
  440. PDLL_ENTRY_POINT_INFO
  441. AVrfpFindDllEntryPoint (
  442. PVOID DllBase
  443. );
  444. BOOLEAN
  445. AVrfpStandardDllEntryPointRoutine (
  446. IN PVOID DllHandle,
  447. IN ULONG Reason,
  448. IN PCONTEXT Context OPTIONAL
  449. );
  450. ULONG
  451. AVrfpDllEntryPointExceptionFilter (
  452. ULONG ExceptionCode,
  453. PVOID ExceptionRecord,
  454. PDLL_ENTRY_POINT_INFO DllInfo
  455. );
  456. NTSTATUS
  457. AVrfpDllInitialize (
  458. VOID
  459. )
  460. /*++
  461. Routine description:
  462. This routine initializes dll entry point hooking structures.
  463. It is called during the PROCESS_VERIFIER for verifier.dll.
  464. It cannot be called during PROCESS_ATTACH because it is too late and
  465. by that time we already need the structures initialized.
  466. Parameters:
  467. None.
  468. Return value:
  469. None.
  470. --*/
  471. {
  472. NTSTATUS Status;
  473. InitializeListHead (&DllLoadListHead);
  474. Status = RtlInitializeCriticalSection (&DllLoadListLock);
  475. return Status;
  476. }
  477. VOID
  478. AVrfpDllLoadCallback (
  479. PWSTR DllName,
  480. PVOID DllBase,
  481. SIZE_T DllSize,
  482. PVOID Reserved
  483. )
  484. /*++
  485. Routine description:
  486. This routine is a dll load callback called by the verifier engine
  487. (from ntdll.dll) whenever a dll gets loaded.
  488. Parameters:
  489. DllName - name of the dll
  490. DllBase - base load address
  491. DllSize - size of the dll
  492. Reserved - pointer to the LDR_DATA_TABLE_ENTRY structure maintained by the
  493. loader for this dll.
  494. Return value:
  495. None.
  496. --*/
  497. {
  498. PLDR_DATA_TABLE_ENTRY Ldr;
  499. PDLL_ENTRY_POINT_INFO Info;
  500. UNREFERENCED_PARAMETER (DllBase);
  501. UNREFERENCED_PARAMETER (DllSize);
  502. Ldr = (PLDR_DATA_TABLE_ENTRY)Reserved;
  503. ASSERT (Ldr != NULL);
  504. //
  505. // Make sure we do not have a null entry point. We will ignore
  506. // these ones. No harm done.
  507. //
  508. if (Ldr->EntryPoint == NULL) {
  509. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DLLMAIN_HOOKING) != 0) {
  510. DbgPrint ("AVRF: %ws: null entry point.\n", DllName);
  511. }
  512. return;
  513. }
  514. else {
  515. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DLLMAIN_HOOKING) != 0) {
  516. DbgPrint ("AVRF: %ws @ %p: entry point @ %p .\n",
  517. DllName, Ldr->DllBase, Ldr->EntryPoint);
  518. }
  519. }
  520. //
  521. // We will change the dll entry point.
  522. //
  523. Info = AVrfpAllocate (sizeof *Info);
  524. if (Info == NULL) {
  525. //
  526. // If we cannot allocate the dll info we will let everything
  527. // continue. We will just not verify this dll entry.
  528. //
  529. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DLLMAIN_HOOKING) != 0) {
  530. DbgPrint ("AVRF: low memory: will not verify entry point for %ws .\n", DllName);
  531. }
  532. return;
  533. }
  534. Info->EntryPoint = (PDLL_INIT_ROUTINE)(Ldr->EntryPoint);
  535. Info->DllBase = Ldr->DllBase;
  536. Info->Ldr = Ldr;
  537. RtlEnterCriticalSection (&DllLoadListLock);
  538. try {
  539. Ldr->EntryPoint = AVrfpStandardDllEntryPointRoutine;
  540. InsertTailList (&DllLoadListHead, &(Info->List));
  541. }
  542. finally {
  543. RtlLeaveCriticalSection (&DllLoadListLock);
  544. }
  545. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DLLMAIN_HOOKING) != 0) {
  546. DbgPrint ("AVRF: hooked dll entry point for dll %ws \n", DllName);
  547. }
  548. }
  549. VOID
  550. AVrfpDllUnloadCallback (
  551. PWSTR DllName,
  552. PVOID DllBase,
  553. SIZE_T DllSize,
  554. PVOID Reserved
  555. )
  556. /*++
  557. Routine description:
  558. This routine is a dll unload callback called by the verifier engine
  559. (from ntdll.dll) whenever a dll gets unloaded.
  560. Parameters:
  561. DllName - name of the dll
  562. DllBase - base load address
  563. DllSize - size of the dll
  564. Reserved - pointer to the LDR_DATA_TABLE_ENTRY structure maintained by the
  565. loader for this dll.
  566. Return value:
  567. None.
  568. --*/
  569. {
  570. PDLL_ENTRY_POINT_INFO Info;
  571. BOOLEAN FoundEntry;
  572. UNREFERENCED_PARAMETER (Reserved);
  573. FoundEntry = FALSE;
  574. Info = NULL;
  575. ASSERT (DllBase != NULL);
  576. //
  577. // Notify anybody interested in checking the fact that DLL's virtual
  578. // region will be discarded.
  579. //
  580. AVrfpFreeMemNotify (VerifierFreeMemTypeUnloadDll,
  581. DllBase,
  582. DllSize,
  583. DllName);
  584. //
  585. // We need to find the dll in our own dll list, remove it from
  586. // the list and free entry point information. There are a few cases
  587. // where there might be no entry there so we have to protect against
  588. // that (null entry point in the first place or low memory).
  589. //
  590. RtlEnterCriticalSection (&DllLoadListLock);
  591. try {
  592. Info = AVrfpFindDllEntryPoint (DllBase);
  593. if (Info) {
  594. RemoveEntryList (&(Info->List));
  595. }
  596. }
  597. finally {
  598. RtlLeaveCriticalSection (&DllLoadListLock);
  599. }
  600. if (Info) {
  601. AVrfpFree (Info);
  602. }
  603. }
  604. PDLL_ENTRY_POINT_INFO
  605. AVrfpFindDllEntryPoint (
  606. PVOID DllBase
  607. )
  608. /*++
  609. Routine description:
  610. This routine searches for a dll entry point descriptor in the list of
  611. descriptors kept by verifier for one that matches the dll base address
  612. passed as a parameter.
  613. Before calling this function the DllLoadListLock must be acquired.
  614. Parameters:
  615. DllBase - dll base load address for the dll to be found.
  616. Return value:
  617. A pointer to a dll descriptor if an entry was found and null otherwise.
  618. --*/
  619. {
  620. PDLL_ENTRY_POINT_INFO Info;
  621. BOOLEAN FoundEntry;
  622. PLIST_ENTRY Current;
  623. FoundEntry = FALSE;
  624. Info = NULL;
  625. ASSERT (DllBase != NULL);
  626. //
  627. // Search for the dll in our own dll list.
  628. //
  629. Current = DllLoadListHead.Flink;
  630. while (Current != &DllLoadListHead) {
  631. Info = CONTAINING_RECORD (Current,
  632. DLL_ENTRY_POINT_INFO,
  633. List);
  634. Current = Current->Flink;
  635. if (Info->DllBase == DllBase) {
  636. FoundEntry = TRUE;
  637. break;
  638. }
  639. }
  640. if (FoundEntry == FALSE) {
  641. return NULL;
  642. }
  643. else {
  644. return Info;
  645. }
  646. }
  647. BOOLEAN
  648. AVrfpStandardDllEntryPointRoutine (
  649. IN PVOID DllHandle,
  650. IN ULONG Reason,
  651. IN PCONTEXT Context OPTIONAL
  652. )
  653. /*++
  654. Routine description:
  655. This routine is the standard DllMain routine that replaces all the entry points
  656. hooked. It will call in turn the original entry point.
  657. Parameters:
  658. Same as the original dll entry point.
  659. Return value:
  660. Same as the original dll entry point.
  661. --*/
  662. {
  663. PDLL_ENTRY_POINT_INFO DllInfo;
  664. BOOLEAN Result;
  665. PAVRF_TLS_STRUCT TlsStruct;
  666. Result = FALSE;
  667. DllInfo = NULL;
  668. //
  669. // Search a dll entry point descriptor for this dll address.
  670. //
  671. RtlEnterCriticalSection (&DllLoadListLock);
  672. try {
  673. DllInfo = AVrfpFindDllEntryPoint (DllHandle);
  674. //
  675. // If we did not manage to find a dll descriptor for this one it is
  676. // weird. For out of memory conditions we do not change the original
  677. // entry point therefore we should never get into this function w/o
  678. // a descriptor in the dll list.
  679. //
  680. if (DllInfo == NULL) {
  681. DbgPrint ("AVRF: warning: no descriptor for DLL loaded @ %p .\n", DllHandle);
  682. ASSERT (DllInfo != NULL);
  683. //
  684. // Simulate a successful return;
  685. //
  686. RtlLeaveCriticalSection (&DllLoadListLock);
  687. return TRUE;
  688. }
  689. else {
  690. //
  691. // If we found a dll entry but the entry point is null we just
  692. // simulate a successful return from DllMain.
  693. //
  694. if (DllInfo->EntryPoint == NULL) {
  695. DbgPrint ("AVRF: warning: null entry point for DLL descriptor @ %p .\n", DllInfo);
  696. ASSERT (DllInfo->EntryPoint != NULL);
  697. RtlLeaveCriticalSection (&DllLoadListLock);
  698. return TRUE;
  699. }
  700. }
  701. }
  702. except (EXCEPTION_EXECUTE_HANDLER) {
  703. }
  704. RtlLeaveCriticalSection (&DllLoadListLock);
  705. //
  706. // Mark this thread as loader lock owner.
  707. // If the real DllMain later on calls WaitForSingleObject
  708. // on another thread handle we will use this flag to detect the issue
  709. // and break into debugger because that other thread will need the
  710. // loader lock when it will call ExitThread.
  711. //
  712. TlsStruct = AVrfpGetVerifierTlsValue();
  713. if (TlsStruct != NULL) {
  714. TlsStruct->Flags |= VRFP_THREAD_FLAGS_LOADER_LOCK_OWNER;
  715. }
  716. //
  717. // Call the real entry point wrapped in try/except.
  718. //
  719. try {
  720. try {
  721. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_DLLMAIN_CALL) != 0) {
  722. DbgPrint ("AVRF: dll entry @ %p (%ws, %x) \n",
  723. DllInfo->EntryPoint,
  724. DllInfo->Ldr->FullDllName.Buffer,
  725. Reason);
  726. }
  727. Result = (DllInfo->EntryPoint) (DllHandle, Reason, Context);
  728. }
  729. except (AVrfpDllEntryPointExceptionFilter (_exception_code(), _exception_info(), DllInfo)) {
  730. NOTHING;
  731. }
  732. }
  733. finally {
  734. if (TlsStruct != NULL) {
  735. TlsStruct->Flags &= ~VRFP_THREAD_FLAGS_LOADER_LOCK_OWNER;
  736. }
  737. }
  738. return Result;
  739. }
  740. ULONG
  741. AVrfpDllEntryPointExceptionFilter (
  742. ULONG ExceptionCode,
  743. PVOID ExceptionRecord,
  744. PDLL_ENTRY_POINT_INFO DllInfo
  745. )
  746. /*++
  747. Routine description:
  748. This routine is the exception filter used to cath exceptions raised
  749. from a dll initialization function.
  750. Parameters:
  751. ExceptionCode - exception code.
  752. ExceptionRecord - exception pointers.
  753. Return value:
  754. Returns EXCEPTION_CONTINUE_SEARCH.
  755. --*/
  756. {
  757. PEXCEPTION_POINTERS Exception;
  758. //
  759. // Skip timeout and breakpoint exceptions.
  760. //
  761. if (ExceptionCode != STATUS_POSSIBLE_DEADLOCK &&
  762. ExceptionCode != STATUS_BREAKPOINT) {
  763. Exception = (PEXCEPTION_POINTERS)ExceptionRecord;
  764. VERIFIER_STOP (APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  765. "unexpected exception raised in DLL entry point routine",
  766. DllInfo->Ldr->BaseDllName.Buffer, "DLL name (use du to dump it)",
  767. Exception->ExceptionRecord, "Exception record (.exr THIS-ADDRESS)",
  768. Exception->ContextRecord, "Context record (.cxr THIS-ADDRESS)",
  769. DllInfo, "Verifier dll descriptor");
  770. }
  771. return EXCEPTION_CONTINUE_SEARCH;
  772. }
  773. VOID
  774. AVrfpVerifyLegalWait (
  775. CONST HANDLE *Handles,
  776. DWORD Count,
  777. BOOL WaitAll
  778. )
  779. {
  780. DWORD Index;
  781. PAVRF_TLS_STRUCT TlsStruct;
  782. NTSTATUS Status;
  783. THREAD_BASIC_INFORMATION ThreadInfo;
  784. BYTE QueryBuffer[200];
  785. POBJECT_TYPE_INFORMATION TypeInfo = (POBJECT_TYPE_INFORMATION)QueryBuffer;
  786. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_HANDLE_CHECKS) == 0) {
  787. goto Done;
  788. }
  789. if (Handles == NULL || Count == 0) {
  790. VERIFIER_STOP (APPLICATION_VERIFIER_INCORRECT_WAIT_CALL | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  791. "incorrect Wait call",
  792. Handles, "Address of object handle(s)",
  793. Count, "Number of handles",
  794. NULL, "",
  795. NULL, "");
  796. }
  797. else {
  798. //
  799. // Check if the current thread owns the loader lock.
  800. //
  801. TlsStruct = AVrfpGetVerifierTlsValue();
  802. for (Index = 0; Index < Count; Index += 1) {
  803. //
  804. // Verify that the handle is not NULL.
  805. //
  806. if (Handles[Index] == NULL) {
  807. VERIFIER_STOP (APPLICATION_VERIFIER_NULL_HANDLE | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  808. "using NULL handle",
  809. NULL, "",
  810. NULL, "",
  811. NULL, "",
  812. NULL, "");
  813. continue;
  814. }
  815. if ((TlsStruct == NULL) ||
  816. ((TlsStruct->Flags & VRFP_THREAD_FLAGS_LOADER_LOCK_OWNER) == 0) ||
  817. (RtlDllShutdownInProgress() != FALSE) ||
  818. (WaitAll == FALSE)) {
  819. continue;
  820. }
  821. //
  822. // The current thread is the loader lock owner.
  823. // Check if any of the objects we are about to wait on is
  824. // a thread in the current process. This would be illegal because
  825. // that thread will need the loader lock when calling ExitThread
  826. // so we will most likely deadlock.
  827. //
  828. Status = NtQueryObject (Handles[Index],
  829. ObjectTypeInformation,
  830. QueryBuffer,
  831. sizeof (QueryBuffer),
  832. NULL);
  833. if (NT_SUCCESS(Status) &&
  834. RtlEqualUnicodeString (&AVrfpThreadObjectName,
  835. &(((POBJECT_TYPE_INFORMATION)TypeInfo)->TypeName),
  836. FALSE)) {
  837. //
  838. // We are trying to wait on this thread handle.
  839. // Check if this thread is in the current process.
  840. //
  841. Status = NtQueryInformationThread (Handles[Index],
  842. ThreadBasicInformation,
  843. &ThreadInfo,
  844. sizeof (ThreadInfo),
  845. NULL);
  846. if (NT_SUCCESS(Status) &&
  847. ThreadInfo.ClientId.UniqueProcess == NtCurrentTeb()->ClientId.UniqueProcess) {
  848. VERIFIER_STOP (APPLICATION_VERIFIER_WAIT_IN_DLLMAIN | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  849. "waiting on a thread handle in DllMain",
  850. Handles[Index], "Thread handle",
  851. NULL, "",
  852. NULL, "",
  853. NULL, "");
  854. }
  855. }
  856. }
  857. }
  858. Done:
  859. NOTHING;
  860. }
  861. /////////////////////////////////////////////////////////////////////
  862. /////////////////////////////////////////////////////// Race verifier
  863. /////////////////////////////////////////////////////////////////////
  864. //
  865. // Race verifier
  866. //
  867. // Race verifier introduces short random delays immediately after
  868. // a thread acquires a resource (successful wait or enter/tryenter
  869. // critical section). The idea behind it is that this will create
  870. // a significant amount of timing randomization in the process.
  871. //
  872. ULONG AVrfpRaceDelayInitialSeed;
  873. ULONG AVrfpRaceDelaySeed;
  874. ULONG AVrfpRaceProbability = 5; // 5%
  875. VOID
  876. AVrfpCreateRandomDelay (
  877. VOID
  878. )
  879. {
  880. LARGE_INTEGER PerformanceCounter;
  881. LARGE_INTEGER TimeOut;
  882. ULONG Random;
  883. if (AVrfpRaceDelayInitialSeed == 0) {
  884. NtQueryPerformanceCounter (&PerformanceCounter, NULL);
  885. AVrfpRaceDelayInitialSeed = PerformanceCounter.LowPart;
  886. AVrfpRaceDelaySeed = AVrfpRaceDelayInitialSeed;
  887. }
  888. Random = RtlRandom (&AVrfpRaceDelaySeed) % 100;
  889. if (Random <= AVrfpRaceProbability) {
  890. //
  891. // A null timeout means the thread will just release
  892. // the rest of the time slice it has on this processor.
  893. //
  894. TimeOut.QuadPart = (LONGLONG)0;
  895. NtDelayExecution (FALSE, &TimeOut);
  896. BUMP_COUNTER (CNT_RACE_DELAYS_INJECTED);
  897. }
  898. else {
  899. BUMP_COUNTER (CNT_RACE_DELAYS_SKIPPED);
  900. }
  901. }
  902. /////////////////////////////////////////////////////////////////////
  903. /////////////////////////////////////////////// First chance AV logic
  904. /////////////////////////////////////////////////////////////////////
  905. VOID
  906. AVrfpCheckFirstChanceException (
  907. struct _EXCEPTION_POINTERS * ExceptionPointers
  908. )
  909. {
  910. DWORD ExceptionCode;
  911. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_FIRST_CHANCE_EXCEPTION_CHECKS) == 0) {
  912. return;
  913. }
  914. ExceptionCode = ExceptionPointers->ExceptionRecord->ExceptionCode;
  915. if (ExceptionCode == STATUS_ACCESS_VIOLATION) {
  916. if (NtCurrentPeb()->BeingDebugged) {
  917. if (ExceptionPointers->ExceptionRecord->NumberParameters > 1) {
  918. if (ExceptionPointers->ExceptionRecord->ExceptionInformation[1] > 0x10000) {
  919. VERIFIER_STOP (APPLICATION_VERIFIER_ACCESS_VIOLATION | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  920. "first chance access violation for current stack trace",
  921. ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
  922. "Invalid address being accessed",
  923. ExceptionPointers->ExceptionRecord->ExceptionAddress,
  924. "Code performing invalid access",
  925. ExceptionPointers->ExceptionRecord,
  926. "Exception record. Use .exr to display it.",
  927. ExceptionPointers->ContextRecord,
  928. "Context record. Use .cxr to display it.");
  929. }
  930. }
  931. }
  932. }
  933. }
  934. /////////////////////////////////////////////////////////////////////
  935. ////////////////////////////////////////////////// Free memory checks
  936. /////////////////////////////////////////////////////////////////////
  937. #define AVRF_FREE_MEMORY_CALLBACKS 16
  938. #define FREE_CALLBACK_OK_TO_CALL 0
  939. #define FREE_CALLBACK_ACTIVE 1
  940. #define FREE_CALLBACK_DELETING 2
  941. LONG AVrfpFreeCallbackState;
  942. LONG AVrfpFreeCallbackCallers;
  943. PVOID AVrfpFreeMemoryCallbacks[AVRF_FREE_MEMORY_CALLBACKS];
  944. NTSTATUS
  945. AVrfpAddFreeMemoryCallback (
  946. VERIFIER_FREE_MEMORY_CALLBACK Callback
  947. )
  948. {
  949. ULONG Index;
  950. PVOID Value;
  951. for (Index = 0; Index < AVRF_FREE_MEMORY_CALLBACKS; Index += 1) {
  952. Value = InterlockedCompareExchangePointer (&(AVrfpFreeMemoryCallbacks[Index]),
  953. Callback,
  954. NULL);
  955. if (Value == NULL) {
  956. return STATUS_SUCCESS;
  957. }
  958. }
  959. DbgPrint ("AVRF: failed to add free memory callback @ %p \n", Callback);
  960. DbgBreakPoint ();
  961. return STATUS_NO_MEMORY;
  962. }
  963. NTSTATUS
  964. AVrfpDeleteFreeMemoryCallback (
  965. VERIFIER_FREE_MEMORY_CALLBACK Callback
  966. )
  967. {
  968. ULONG Index;
  969. PVOID Value;
  970. LONG State;
  971. //
  972. // Spin until we can delete a callback. If some region got freed and some
  973. // callbacks are running we will wait until they finish.
  974. //
  975. do {
  976. State = InterlockedCompareExchange (&AVrfpFreeCallbackState,
  977. FREE_CALLBACK_DELETING,
  978. FREE_CALLBACK_OK_TO_CALL);
  979. } while (State != FREE_CALLBACK_OK_TO_CALL);
  980. for (Index = 0; Index < AVRF_FREE_MEMORY_CALLBACKS; Index += 1) {
  981. Value = InterlockedCompareExchangePointer (&(AVrfpFreeMemoryCallbacks[Index]),
  982. NULL,
  983. Callback);
  984. if (Value == Callback) {
  985. InterlockedExchange (&AVrfpFreeCallbackState,
  986. FREE_CALLBACK_OK_TO_CALL);
  987. return STATUS_SUCCESS;
  988. }
  989. }
  990. DbgPrint ("AVRF: attempt to delete invalid free memory callback @ %p \n", Callback);
  991. DbgBreakPoint ();
  992. InterlockedExchange (&AVrfpFreeCallbackState,
  993. FREE_CALLBACK_OK_TO_CALL);
  994. return STATUS_UNSUCCESSFUL;
  995. }
  996. VOID
  997. AVrfpCallFreeMemoryCallbacks (
  998. PVOID StartAddress,
  999. SIZE_T RegionSize,
  1000. PWSTR UnloadedDllName
  1001. )
  1002. {
  1003. ULONG Index;
  1004. PVOID Value;
  1005. LONG State;
  1006. LONG Callers;
  1007. //
  1008. // If some thread is deleting a callback then we will not call any
  1009. // callback. Since this is a rare event (callbacks do not get
  1010. // deleted often) we will not lose bugs (maybe a few weird ones).
  1011. //
  1012. // If zero or more threads execute callbacks it is ok to call them also
  1013. // from this thread.
  1014. //
  1015. //
  1016. // Callers++ will prevent the State to go from Active to OkToCall.
  1017. // Therefore we block any deletes.
  1018. //
  1019. InterlockedIncrement (&AVrfpFreeCallbackCallers);
  1020. State = InterlockedCompareExchange (&AVrfpFreeCallbackState,
  1021. FREE_CALLBACK_ACTIVE,
  1022. FREE_CALLBACK_OK_TO_CALL);
  1023. if (State != FREE_CALLBACK_DELETING) {
  1024. for (Index = 0; Index < AVRF_FREE_MEMORY_CALLBACKS; Index += 1) {
  1025. Value = InterlockedCompareExchangePointer (&(AVrfpFreeMemoryCallbacks[Index]),
  1026. NULL,
  1027. NULL);
  1028. if (Value != NULL) {
  1029. ((VERIFIER_FREE_MEMORY_CALLBACK)Value) (StartAddress,
  1030. RegionSize,
  1031. UnloadedDllName);
  1032. }
  1033. }
  1034. //
  1035. // Exit protocol. If callers == 1 then this thread needs to change from Active
  1036. // to OkToCall. This way we give green light for possible deletes.
  1037. //
  1038. Callers = InterlockedCompareExchange (&AVrfpFreeCallbackCallers,
  1039. 0,
  1040. 1);
  1041. if (Callers == 1) {
  1042. InterlockedExchange (&AVrfpFreeCallbackState,
  1043. FREE_CALLBACK_OK_TO_CALL);
  1044. }
  1045. else {
  1046. InterlockedDecrement (&AVrfpFreeCallbackCallers);
  1047. }
  1048. }
  1049. else {
  1050. //
  1051. // Some other thread deletes callbacks.
  1052. // We will skip them this time.
  1053. //
  1054. InterlockedDecrement (&AVrfpFreeCallbackCallers);
  1055. }
  1056. }
  1057. BOOL
  1058. AVrfpFreeMemSanityChecks (
  1059. VERIFIER_DLL_FREEMEM_TYPE FreeMemType,
  1060. PVOID StartAddress,
  1061. SIZE_T RegionSize,
  1062. PWSTR UnloadedDllName
  1063. )
  1064. {
  1065. BOOL Success = TRUE;
  1066. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) == 0) {
  1067. goto Done;
  1068. }
  1069. //
  1070. // Break for invalid StartAddress/RegionSize combinations.
  1071. //
  1072. if ((AVrfpSysBasicInfo.MaximumUserModeAddress <= (ULONG_PTR)StartAddress) ||
  1073. ((AVrfpSysBasicInfo.MaximumUserModeAddress - (ULONG_PTR)StartAddress) < RegionSize)) {
  1074. Success = FALSE;
  1075. switch (FreeMemType) {
  1076. case VerifierFreeMemTypeFreeHeap:
  1077. //
  1078. // Nothing. Let page heap handle the bogus block.
  1079. //
  1080. break;
  1081. case VerifierFreeMemTypeVirtualFree:
  1082. case VerifierFreeMemTypeUnmap:
  1083. //
  1084. // Our caller is AVrfpFreeVirtualMemNotify and that should have
  1085. // signaled this error already.
  1086. //
  1087. break;
  1088. case VerifierFreeMemTypeUnloadDll:
  1089. ASSERT (UnloadedDllName != NULL);
  1090. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1091. "Unloading DLL with invalid size or start address",
  1092. StartAddress, "Allocation base address",
  1093. RegionSize, "Memory region size",
  1094. UnloadedDllName, "DLL name address. Use du to dump it.",
  1095. NULL, "" );
  1096. break;
  1097. default:
  1098. ASSERT (FALSE );
  1099. break;
  1100. }
  1101. }
  1102. else {
  1103. //
  1104. // Verify that we are not trying to free a portion of the current thread's stack (!)
  1105. //
  1106. if (((StartAddress >= NtCurrentTeb()->DeallocationStack) && (StartAddress < NtCurrentTeb()->NtTib.StackBase)) ||
  1107. ((StartAddress < NtCurrentTeb()->DeallocationStack) && ((PCHAR)StartAddress + RegionSize > (PCHAR)NtCurrentTeb()->DeallocationStack)))
  1108. {
  1109. Success = FALSE;
  1110. switch (FreeMemType) {
  1111. case VerifierFreeMemTypeFreeHeap:
  1112. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1113. "Freeing heap memory block inside current thread's stack address range",
  1114. StartAddress, "Allocation base address",
  1115. RegionSize, "Memory region size",
  1116. NtCurrentTeb()->DeallocationStack, "Stack low limit address",
  1117. NtCurrentTeb()->NtTib.StackBase, "Stack high limit address" );
  1118. break;
  1119. case VerifierFreeMemTypeVirtualFree:
  1120. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1121. "Freeing memory block inside current thread's stack address range",
  1122. StartAddress, "Allocation base address",
  1123. RegionSize, "Memory region size",
  1124. NtCurrentTeb()->DeallocationStack, "Stack low limit address",
  1125. NtCurrentTeb()->NtTib.StackBase, "Stack high limit address" );
  1126. break;
  1127. case VerifierFreeMemTypeUnloadDll:
  1128. ASSERT (UnloadedDllName != NULL);
  1129. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1130. "Unloading DLL inside current thread's stack address range",
  1131. StartAddress, "Allocation base address",
  1132. RegionSize, "Memory region size",
  1133. UnloadedDllName, "DLL name address. Use du to dump it.",
  1134. NtCurrentTeb()->DeallocationStack, "Stack low limit address");
  1135. break;
  1136. case VerifierFreeMemTypeUnmap:
  1137. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1138. "Unmapping memory region inside current thread's stack address range",
  1139. StartAddress, "Allocation base address",
  1140. RegionSize, "Memory region size",
  1141. NtCurrentTeb()->DeallocationStack, "Stack low limit address",
  1142. NtCurrentTeb()->NtTib.StackBase, "Stack high limit address" );
  1143. break;
  1144. default:
  1145. ASSERT (FALSE );
  1146. break;
  1147. }
  1148. }
  1149. }
  1150. Done:
  1151. return Success;
  1152. }
  1153. VOID
  1154. AVrfpFreeMemNotify (
  1155. VERIFIER_DLL_FREEMEM_TYPE FreeMemType,
  1156. PVOID StartAddress,
  1157. SIZE_T RegionSize,
  1158. PWSTR UnloadedDllName
  1159. )
  1160. {
  1161. BOOL Success;
  1162. //
  1163. // Simple checks for allocation start address and size.
  1164. //
  1165. Success = AVrfpFreeMemSanityChecks (FreeMemType,
  1166. StartAddress,
  1167. RegionSize,
  1168. UnloadedDllName);
  1169. if (Success != FALSE) {
  1170. //
  1171. // Verify if there are any active critical section
  1172. // in the memory we are freeing.
  1173. //
  1174. AVrfpFreeMemLockChecks (FreeMemType,
  1175. StartAddress,
  1176. RegionSize,
  1177. UnloadedDllName);
  1178. }
  1179. //
  1180. // Call free memory callbacks.
  1181. //
  1182. AVrfpCallFreeMemoryCallbacks (StartAddress,
  1183. RegionSize,
  1184. UnloadedDllName);
  1185. }
  1186. /////////////////////////////////////////////////////////////////////
  1187. ////////////////////////////////////////// Verifier private heap APIs
  1188. /////////////////////////////////////////////////////////////////////
  1189. PVOID AVrfpHeap;
  1190. PVOID
  1191. AVrfpAllocate (
  1192. SIZE_T Size
  1193. )
  1194. {
  1195. ASSERT (AVrfpHeap != NULL);
  1196. ASSERT (Size > 0);
  1197. return RtlAllocateHeap (AVrfpHeap,
  1198. HEAP_ZERO_MEMORY,
  1199. Size);
  1200. }
  1201. VOID
  1202. AVrfpFree (
  1203. PVOID Address
  1204. )
  1205. {
  1206. ASSERT (AVrfpHeap != NULL);
  1207. ASSERT (Address != NULL);
  1208. RtlFreeHeap (AVrfpHeap,
  1209. 0,
  1210. Address);
  1211. }
  1212. /////////////////////////////////////////////////////////////////////
  1213. /////////////////////////////////////////////////////// Call trackers
  1214. /////////////////////////////////////////////////////////////////////
  1215. PAVRF_TRACKER AVrfThreadTracker;
  1216. PAVRF_TRACKER AVrfHeapTracker;
  1217. PAVRF_TRACKER AVrfVspaceTracker;
  1218. NTSTATUS
  1219. AVrfCreateTrackers (
  1220. VOID
  1221. )
  1222. {
  1223. if ((AVrfThreadTracker = AVrfCreateTracker (16)) == NULL) {
  1224. goto CLEANUP_AND_FAIL;
  1225. }
  1226. if ((AVrfHeapTracker = AVrfCreateTracker (8192)) == NULL) {
  1227. goto CLEANUP_AND_FAIL;
  1228. }
  1229. if ((AVrfVspaceTracker = AVrfCreateTracker (8192)) == NULL) {
  1230. goto CLEANUP_AND_FAIL;
  1231. }
  1232. return STATUS_SUCCESS;
  1233. CLEANUP_AND_FAIL:
  1234. AVrfDestroyTracker (AVrfThreadTracker);
  1235. AVrfDestroyTracker (AVrfHeapTracker);
  1236. AVrfDestroyTracker (AVrfVspaceTracker);
  1237. return STATUS_NO_MEMORY;
  1238. }