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.

1843 lines
50 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. vspace.c
  5. Abstract:
  6. This module implements verification functions for
  7. virtual address space management interfaces.
  8. Author:
  9. Silviu Calinoiu (SilviuC) 22-Feb-2001
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #include "verifier.h"
  14. #include "support.h"
  15. #include "critsect.h"
  16. #include "faults.h"
  17. #include "vspace.h"
  18. #include "public.h"
  19. #include "logging.h"
  20. //
  21. // Internal functions declarations
  22. //
  23. VOID
  24. AVrfpFreeVirtualMemNotify (
  25. HANDLE ProcessHandle,
  26. VERIFIER_DLL_FREEMEM_TYPE FreeMemType,
  27. PVOID BaseAddress,
  28. PSIZE_T RegionSize,
  29. ULONG VirtualFreeType
  30. );
  31. NTSTATUS
  32. AVrfpGetVadInformation (
  33. PVOID Address,
  34. PVOID * VadAddress,
  35. PSIZE_T VadSize
  36. );
  37. NTSTATUS
  38. AVrfpIsCurrentProcessHandle (
  39. HANDLE ProcessHandle,
  40. PLOGICAL IsCurrent
  41. );
  42. NTSTATUS
  43. AVrfpVsTrackAddRegion (
  44. ULONG_PTR Address,
  45. ULONG_PTR Size
  46. );
  47. NTSTATUS
  48. AVrfpVsTrackDeleteRegion (
  49. ULONG_PTR Address
  50. );
  51. VOID
  52. AVrfpVsTrackerLock (
  53. VOID
  54. );
  55. VOID
  56. AVrfpVsTrackerUnlock (
  57. VOID
  58. );
  59. //NTSYSCALLAPI
  60. NTSTATUS
  61. NTAPI
  62. AVrfpNtAllocateVirtualMemory(
  63. IN HANDLE ProcessHandle,
  64. IN OUT PVOID *BaseAddress,
  65. IN ULONG_PTR ZeroBits,
  66. IN OUT PSIZE_T RegionSize,
  67. IN ULONG AllocationType,
  68. IN ULONG Protect
  69. )
  70. {
  71. NTSTATUS Status;
  72. LOGICAL ShouldTrack = FALSE;
  73. BUMP_COUNTER (CNT_VIRTUAL_ALLOC_CALLS);
  74. if (SHOULD_FAULT_INJECT(CLS_VIRTUAL_ALLOC_APIS)) {
  75. BUMP_COUNTER (CNT_VIRTUAL_ALLOC_FAILS);
  76. CHECK_BREAK (BRK_VIRTUAL_ALLOC_FAIL);
  77. return STATUS_NO_MEMORY;
  78. }
  79. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  80. if (BaseAddress == NULL || RegionSize == NULL) {
  81. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_ALLOCMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  82. "Incorrect virtual alloc call",
  83. BaseAddress, "Pointer to allocation base address",
  84. RegionSize, "Pointer to memory region size",
  85. NULL, "",
  86. NULL, "" );
  87. }
  88. else {
  89. //
  90. // Allocate top-down for 64 bit systems or 3Gb systems.
  91. //
  92. if (*BaseAddress == NULL && AVrfpSysBasicInfo.MaximumUserModeAddress > (ULONG_PTR)0x80000000) {
  93. AllocationType |= MEM_TOP_DOWN;
  94. }
  95. }
  96. }
  97. //
  98. // Figure out if this is an allocation that should go into the
  99. // virtual space tracker.
  100. //
  101. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING) != 0) {
  102. if ((AllocationType & (MEM_PHYSICAL | MEM_RESET)) == 0) {
  103. if ((AllocationType & (MEM_RESERVE | MEM_COMMIT)) != 0) {
  104. Status = AVrfpIsCurrentProcessHandle (ProcessHandle, &ShouldTrack);
  105. if (! NT_SUCCESS(Status)) {
  106. return Status;
  107. }
  108. }
  109. }
  110. }
  111. //
  112. // Call the real function.
  113. //
  114. Status = NtAllocateVirtualMemory (ProcessHandle,
  115. BaseAddress,
  116. ZeroBits,
  117. RegionSize,
  118. AllocationType,
  119. Protect);
  120. if (NT_SUCCESS(Status)) {
  121. AVrfLogInTracker (AVrfVspaceTracker,
  122. TRACK_VIRTUAL_ALLOCATE,
  123. *BaseAddress,
  124. (PVOID)*RegionSize,
  125. (PVOID)(ULONG_PTR)AllocationType,
  126. (PVOID)(ULONG_PTR)Protect,
  127. _ReturnAddress());
  128. //
  129. // ShouldTrack is TRUE only if RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING bit is
  130. // set therefore there is no need to test this again.
  131. //
  132. if (ShouldTrack) {
  133. PVOID VadAddress;
  134. SIZE_T VadSize;
  135. Status = AVrfpGetVadInformation (*BaseAddress,
  136. &VadAddress,
  137. &VadSize);
  138. if (NT_SUCCESS(Status)) {
  139. AVrfpVsTrackerLock ();
  140. AVrfpVsTrackAddRegion ((ULONG_PTR)VadAddress, VadSize);
  141. AVrfpVsTrackerUnlock ();
  142. }
  143. }
  144. }
  145. return Status;
  146. }
  147. //NTSYSCALLAPI
  148. NTSTATUS
  149. NTAPI
  150. AVrfpNtFreeVirtualMemory(
  151. IN HANDLE ProcessHandle,
  152. IN OUT PVOID *BaseAddress,
  153. IN OUT PSIZE_T RegionSize,
  154. IN ULONG FreeType
  155. )
  156. {
  157. NTSTATUS Status;
  158. //
  159. // Protect ourselves against invalid calls to NtFreeVirtualMemory
  160. // with a NULL RegionSize or BaseAddress pointers. Note that this will
  161. // never happen if the caller is using the Win32 VirtualFree.
  162. //
  163. if (RegionSize == NULL || BaseAddress == NULL) {
  164. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  165. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  166. "Freeing virtual memory block with invalid size or start address",
  167. BaseAddress, "Pointer to allocation base address",
  168. RegionSize, "Pointer to memory region size",
  169. NULL, "",
  170. NULL, "" );
  171. }
  172. }
  173. else {
  174. //
  175. // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both.
  176. //
  177. if (FreeType != MEM_DECOMMIT && FreeType != MEM_RELEASE) {
  178. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  179. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  180. "Incorrect FreeType parameter for VirtualFree operation",
  181. FreeType, "Incorrect value used by the application",
  182. MEM_DECOMMIT, "Expected correct value 1",
  183. MEM_RELEASE, "Expected correct value 2",
  184. NULL, "" );
  185. }
  186. }
  187. else {
  188. AVrfpFreeVirtualMemNotify (ProcessHandle,
  189. VerifierFreeMemTypeVirtualFree,
  190. *BaseAddress,
  191. RegionSize,
  192. FreeType);
  193. }
  194. }
  195. //
  196. // Call the real function.
  197. //
  198. Status = NtFreeVirtualMemory (ProcessHandle,
  199. BaseAddress,
  200. RegionSize,
  201. FreeType);
  202. if (NT_SUCCESS(Status)) {
  203. AVrfLogInTracker (AVrfVspaceTracker,
  204. TRACK_VIRTUAL_FREE,
  205. *BaseAddress,
  206. (PVOID)*RegionSize,
  207. (PVOID)(ULONG_PTR)FreeType,
  208. NULL,
  209. _ReturnAddress());
  210. //
  211. // If VS tracking is on check if this a free operation that should
  212. // be tracked.
  213. //
  214. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING) != 0) {
  215. //
  216. // If this is a VS release in the current process we will try to track
  217. // it. If we got an error while figuring out if this is a handle for
  218. // the current process we just skip this free. The VS tracker is
  219. // resilient to alloc/free misses.
  220. //
  221. if ((FreeType & MEM_RELEASE) != 0) {
  222. LOGICAL SameProcess;
  223. NTSTATUS IsCurrentProcessStatus;
  224. IsCurrentProcessStatus = AVrfpIsCurrentProcessHandle (ProcessHandle,
  225. &SameProcess);
  226. if (NT_SUCCESS(IsCurrentProcessStatus)) {
  227. if (SameProcess) {
  228. AVrfpVsTrackerLock ();
  229. AVrfpVsTrackDeleteRegion ((ULONG_PTR)(*BaseAddress));
  230. AVrfpVsTrackerUnlock ();
  231. }
  232. }
  233. }
  234. }
  235. }
  236. return Status;
  237. }
  238. //NTSYSCALLAPI
  239. NTSTATUS
  240. NTAPI
  241. AVrfpNtMapViewOfSection(
  242. IN HANDLE SectionHandle,
  243. IN HANDLE ProcessHandle,
  244. IN OUT PVOID *BaseAddress,
  245. IN ULONG_PTR ZeroBits,
  246. IN SIZE_T CommitSize,
  247. IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
  248. IN OUT PSIZE_T ViewSize,
  249. IN SECTION_INHERIT InheritDisposition,
  250. IN ULONG AllocationType,
  251. IN ULONG Protect
  252. )
  253. {
  254. NTSTATUS Status;
  255. BUMP_COUNTER (CNT_MAP_VIEW_CALLS);
  256. if (SHOULD_FAULT_INJECT(CLS_MAP_VIEW_APIS)) {
  257. BUMP_COUNTER (CNT_MAP_VIEW_FAILS);
  258. CHECK_BREAK (BRK_MAP_VIEW_FAIL);
  259. return STATUS_NO_MEMORY;
  260. }
  261. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  262. if (BaseAddress == NULL || ViewSize == NULL) {
  263. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_MAPVIEW | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  264. "Incorrect map view call",
  265. BaseAddress, "Pointer to mapping base address",
  266. ViewSize, "Pointer to view size",
  267. NULL, "",
  268. NULL, "" );
  269. }
  270. else {
  271. //
  272. // Allocate top-down for 64 bit systems or 3Gb systems.
  273. //
  274. if (*BaseAddress == NULL && AVrfpSysBasicInfo.MaximumUserModeAddress > (ULONG_PTR)0x80000000) {
  275. AllocationType |= MEM_TOP_DOWN;
  276. }
  277. }
  278. }
  279. Status = NtMapViewOfSection (SectionHandle,
  280. ProcessHandle,
  281. BaseAddress,
  282. ZeroBits,
  283. CommitSize,
  284. SectionOffset,
  285. ViewSize,
  286. InheritDisposition,
  287. AllocationType,
  288. Protect);
  289. if (NT_SUCCESS(Status)) {
  290. AVrfLogInTracker (AVrfVspaceTracker,
  291. TRACK_MAP_VIEW_OF_SECTION,
  292. *BaseAddress,
  293. (PVOID)*ViewSize,
  294. (PVOID)(ULONG_PTR)AllocationType,
  295. (PVOID)(ULONG_PTR)Protect,
  296. _ReturnAddress());
  297. }
  298. return Status;
  299. }
  300. //NTSYSCALLAPI
  301. NTSTATUS
  302. NTAPI
  303. AVrfpNtUnmapViewOfSection(
  304. IN HANDLE ProcessHandle,
  305. IN PVOID BaseAddress
  306. )
  307. {
  308. NTSTATUS Status;
  309. AVrfpFreeVirtualMemNotify (ProcessHandle,
  310. VerifierFreeMemTypeUnmap,
  311. BaseAddress,
  312. NULL,
  313. 0);
  314. //
  315. // Unmap the memory.
  316. //
  317. Status = NtUnmapViewOfSection (ProcessHandle,
  318. BaseAddress);
  319. if (NT_SUCCESS(Status)) {
  320. AVrfLogInTracker (AVrfVspaceTracker,
  321. TRACK_UNMAP_VIEW_OF_SECTION,
  322. BaseAddress,
  323. NULL,
  324. NULL,
  325. NULL,
  326. _ReturnAddress());
  327. }
  328. return Status;
  329. }
  330. //NTSYSCALLAPI
  331. NTSTATUS
  332. NTAPI
  333. AVrfpNtCreateSection (
  334. OUT PHANDLE SectionHandle,
  335. IN ACCESS_MASK DesiredAccess,
  336. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  337. IN PLARGE_INTEGER MaximumSize OPTIONAL,
  338. IN ULONG SectionPageProtection,
  339. IN ULONG AllocationAttributes,
  340. IN HANDLE FileHandle OPTIONAL
  341. )
  342. {
  343. NTSTATUS Status;
  344. Status = NtCreateSection (SectionHandle,
  345. DesiredAccess,
  346. ObjectAttributes,
  347. MaximumSize,
  348. SectionPageProtection,
  349. AllocationAttributes,
  350. FileHandle);
  351. return Status;
  352. }
  353. //NTSYSCALLAPI
  354. NTSTATUS
  355. NTAPI
  356. AVrfpNtOpenSection(
  357. OUT PHANDLE SectionHandle,
  358. IN ACCESS_MASK DesiredAccess,
  359. IN POBJECT_ATTRIBUTES ObjectAttributes
  360. )
  361. {
  362. NTSTATUS Status;
  363. Status = NtOpenSection (SectionHandle,
  364. DesiredAccess,
  365. ObjectAttributes);
  366. return Status;
  367. }
  368. VOID
  369. AVrfpFreeVirtualMemNotify (
  370. HANDLE ProcessHandle,
  371. VERIFIER_DLL_FREEMEM_TYPE FreeMemType,
  372. PVOID BaseAddress,
  373. PSIZE_T RegionSize,
  374. ULONG VirtualFreeType
  375. )
  376. /*++
  377. Routine description:
  378. This routine is called when a portion of virtual space gets freed (free
  379. or unmap). It will make some sanity checks of the free operation and then
  380. it will call the common `memory free' notification routine (the one
  381. called for any free: dll unload, heap free, etc.).
  382. Parameters:
  383. ProcessHandle: process handle.
  384. FreeMemType: type of free. The function is called only with
  385. VerifierFreeMemTypeVirtualFree or VerifierFreeMemTypeVirtualUnmap.
  386. BaseAddress: start address.
  387. RegionSize: region size.
  388. VirtualFreeType: type of free operation requested by VirtualFree or UnmapView.
  389. Return value:
  390. None.
  391. --*/
  392. {
  393. NTSTATUS Status;
  394. PVOID FreedBaseAddress;
  395. SIZE_T FreedSize;
  396. SIZE_T InfoLength;
  397. MEMORY_BASIC_INFORMATION MemoryInformation;
  398. LOGICAL IsCurrentProcessHandle;
  399. //
  400. // Query the size of the allocation and verify that the memory
  401. // is not free already.
  402. //
  403. FreedBaseAddress = PAGE_ALIGN( BaseAddress );
  404. Status = NtQueryVirtualMemory (ProcessHandle,
  405. FreedBaseAddress,
  406. MemoryBasicInformation,
  407. &MemoryInformation,
  408. sizeof (MemoryInformation),
  409. &InfoLength);
  410. if (!NT_SUCCESS (Status)) {
  411. if (AVrfpProvider.VerifierDebug != 0) {
  412. DbgPrint ("AVrfpFreeVirtualMemNotify: NtQueryVirtualMemory( %p ) failed %x\n",
  413. FreedBaseAddress,
  414. Status);
  415. }
  416. }
  417. else {
  418. if (MemoryInformation.State == MEM_FREE) {
  419. //
  420. // We are trying to free memory that is already freed.
  421. // This can indicate a nasty bug in the app because the current thread
  422. // is probably using a stale pointer and this memory could have been
  423. // reused for something else...
  424. //
  425. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  426. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  427. "Trying to free virtual memory block that is already free",
  428. BaseAddress, "Memory block address",
  429. NULL, "",
  430. NULL, "",
  431. NULL, "" );
  432. }
  433. }
  434. else {
  435. //
  436. // Find out if we are freeing memory in the current process
  437. // or in another process. For the cross-process case we are not
  438. // trying to catch any other possible bugs because we can get confused
  439. // if the current process is wow64 and the target is ia64, etc.
  440. //
  441. Status = AVrfpIsCurrentProcessHandle (ProcessHandle,
  442. &IsCurrentProcessHandle);
  443. if (NT_SUCCESS(Status) && IsCurrentProcessHandle) {
  444. //
  445. // For VirtualFree (MEM_RELEASE, RegionSize == 0) or UnmapViewOfFile
  446. // the whole VAD will be freed so we will use its size.
  447. //
  448. if ((FreeMemType == VerifierFreeMemTypeUnmap) ||
  449. ((FreeMemType == VerifierFreeMemTypeVirtualFree) &&
  450. (((VirtualFreeType & MEM_RELEASE) != 0) && *RegionSize == 0))) {
  451. FreedSize = MemoryInformation.RegionSize;
  452. }
  453. else {
  454. ASSERT (RegionSize != NULL);
  455. FreedSize = *RegionSize;
  456. }
  457. //
  458. // Sanity checks for the block start address and size.
  459. // These checks can be integrated in AVrfpFreeMemNotify
  460. // but we want to make sure we are not using values that
  461. // don't make sense in the FreedSize computation below.
  462. //
  463. if ((AVrfpSysBasicInfo.MaximumUserModeAddress <= (ULONG_PTR)FreedBaseAddress) ||
  464. ((AVrfpSysBasicInfo.MaximumUserModeAddress - (ULONG_PTR)FreedBaseAddress) < FreedSize)) {
  465. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  466. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  467. "Freeing virtual memory block with invalid size or start address",
  468. FreedBaseAddress, "Memory block address",
  469. FreedSize, "Memory region size",
  470. NULL, "",
  471. NULL, "" );
  472. }
  473. }
  474. else {
  475. FreedSize = (PCHAR)BaseAddress + FreedSize - (PCHAR)FreedBaseAddress;
  476. FreedSize = ROUND_UP( FreedSize, PAGE_SIZE );
  477. //
  478. // Perform the rest of the checks, common for all memory free operations.
  479. // E.g.:
  480. // - is this memory block part of the current thread's stack?
  481. // - do we have active critical sections inside this memory block?
  482. //
  483. AVrfpFreeMemNotify (FreeMemType,
  484. FreedBaseAddress,
  485. FreedSize,
  486. NULL);
  487. }
  488. }
  489. }
  490. }
  491. }
  492. NTSTATUS
  493. AVrfpIsCurrentProcessHandle (
  494. HANDLE ProcessHandle,
  495. PLOGICAL IsCurrent
  496. )
  497. /*++
  498. Routine description:
  499. This routine figures out if a handle represents the current process'
  500. handle. This means it is either a pseudohandle or a handle obtained
  501. by calling OpenProcess().
  502. Parameters:
  503. ProcessHandle: handle to figure out.
  504. IsCurrent: address of a boolean to pass back the result.
  505. Return value:
  506. STATUS_SUCCESS if the function managed to put a meaningful value in
  507. `*IsCurrent'. Various status errors otherwise.
  508. --*/
  509. {
  510. NTSTATUS Status;
  511. PROCESS_BASIC_INFORMATION BasicInfo;
  512. if (NtCurrentProcess() == ProcessHandle) {
  513. *IsCurrent = TRUE;
  514. return STATUS_SUCCESS;
  515. }
  516. Status = NtQueryInformationProcess (ProcessHandle,
  517. ProcessBasicInformation,
  518. &BasicInfo,
  519. sizeof(BasicInfo),
  520. NULL);
  521. if (! NT_SUCCESS(Status)) {
  522. return Status;
  523. }
  524. if (BasicInfo.UniqueProcessId == (ULONG_PTR)(NtCurrentTeb()->ClientId.UniqueProcess)) {
  525. *IsCurrent = TRUE;
  526. }
  527. else {
  528. *IsCurrent = FALSE;
  529. }
  530. return STATUS_SUCCESS;
  531. }
  532. /////////////////////////////////////////////////////////////////////
  533. ////////////////////////////////////// Virtual space trackker support
  534. /////////////////////////////////////////////////////////////////////
  535. //
  536. // Unexpected frees/allocs happen when one operation happens in a tracked
  537. // dll and the pair operation happens in ntdll.dll, kernel mode or
  538. // cross-process. For example the allocation is made by a kernel mode
  539. // component and the free is done in some dll. The virtual space tracker
  540. // must be resilient to these situations in order to work for any type of
  541. // process.
  542. //
  543. RTL_CRITICAL_SECTION AVrfpVsTrackLock;
  544. LIST_ENTRY AVrfpVsTrackList;
  545. LONG AVrfpVsTrackRegionCount;
  546. SIZE_T AVrfpVsTrackMemoryTotal;
  547. LOGICAL AVrfpVsTrackDisabled;
  548. VOID
  549. AVrfpVsTrackerLock (
  550. VOID
  551. )
  552. {
  553. RtlEnterCriticalSection (&AVrfpVsTrackLock);
  554. }
  555. VOID
  556. AVrfpVsTrackerUnlock (
  557. VOID
  558. )
  559. {
  560. RtlLeaveCriticalSection (&AVrfpVsTrackLock);
  561. }
  562. NTSTATUS
  563. AVrfpVsTrackInitialize (
  564. VOID
  565. )
  566. /*++
  567. Routine description:
  568. This routine initializes virtual space tracker structures.
  569. Parameters:
  570. None.
  571. Return value:
  572. STATUS_SUCCESS if successful. Various status errors otherwise.
  573. --*/
  574. {
  575. NTSTATUS Status;
  576. InitializeListHead (&AVrfpVsTrackList);
  577. Status = RtlInitializeCriticalSection (&AVrfpVsTrackLock);
  578. return Status;
  579. }
  580. NTSTATUS
  581. AVrfpVsTrackAddRegion (
  582. ULONG_PTR Address,
  583. ULONG_PTR Size
  584. )
  585. /*++
  586. Routine description:
  587. This routine adds a new virtual space region to the VS tracker. If there is
  588. already a region having exactly the same characteristics (address, size)
  589. the function does not do anything and returns successfully.
  590. The function is called with the VS track lock acquired.
  591. Parameters:
  592. Address: start address of the new virtual space region.
  593. Size: size of the new virtual space region.
  594. Return value:
  595. STATUS_SUCCESS if successful.
  596. --*/
  597. {
  598. PAVRF_VSPACE_REGION Region;
  599. PLIST_ENTRY Current;
  600. PAVRF_VSPACE_REGION NewRegion;
  601. LOGICAL ClashFound;
  602. if (AVrfpVsTrackDisabled) {
  603. return STATUS_UNSUCCESSFUL;
  604. }
  605. //
  606. // Due to the fact that only virtual space operations coming from
  607. // DLLs (except ntdll.dll) are hooked this routine must be resilient
  608. // to various failures. For example if we try to add a region that
  609. // clashes with an existing region within the tracker it probably means
  610. // the free for the existing region has been missed.
  611. //
  612. ClashFound = FALSE;
  613. Current = AVrfpVsTrackList.Flink;
  614. NewRegion = NULL;
  615. while (Current != &AVrfpVsTrackList) {
  616. Region = CONTAINING_RECORD (Current,
  617. AVRF_VSPACE_REGION,
  618. List);
  619. if (Address < Region->Address + Region->Size) {
  620. if (Address + Size > Region->Address) {
  621. //
  622. // We will recycle `Region' since we missed its free.
  623. //
  624. AVrfpVsTrackRegionCount -= 1;
  625. AVrfpVsTrackMemoryTotal -= Region->Size;
  626. ClashFound = TRUE;
  627. NewRegion = Region;
  628. break;
  629. }
  630. else {
  631. //
  632. // We will add a new region in front of `Region'.
  633. //
  634. break;
  635. }
  636. }
  637. else {
  638. //
  639. // Move on to the next region in the list.
  640. //
  641. Current = Current->Flink;
  642. }
  643. }
  644. //
  645. // We need to create a new region before `Region' if
  646. // NewRegion is null.
  647. //
  648. if (NewRegion == NULL) {
  649. NewRegion = AVrfpAllocate (sizeof *NewRegion);
  650. }
  651. if (NewRegion == NULL) {
  652. //
  653. // Well, we could not allocate a new VS tracker node. Since add/delete
  654. // are resilient to these misses we will let it go.
  655. //
  656. return STATUS_NO_MEMORY;
  657. }
  658. //
  659. // We fill the new virtual space region with information
  660. // and then return.
  661. //
  662. NewRegion->Address = Address;
  663. NewRegion->Size = Size;
  664. RtlCaptureStackBackTrace (3,
  665. MAX_TRACE_DEPTH,
  666. NewRegion->Trace,
  667. NULL);
  668. AVrfpVsTrackRegionCount += 1;
  669. AVrfpVsTrackMemoryTotal += NewRegion->Size;
  670. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_SHOW_VSPACE_TRACKING)) {
  671. DbgPrint ("AVRF: adding virtual space region @ %p (size %p) \n", Address, Size);
  672. }
  673. if (Current != &AVrfpVsTrackList) {
  674. //
  675. // We will add the new region before the current region in the list
  676. // traversal if this is a new region to be inserted and we do not
  677. // just recycle a clashing region.
  678. //
  679. // (Current->Blink)
  680. // <== (NewRegion->List)
  681. // Current
  682. //
  683. if (ClashFound == FALSE) {
  684. NewRegion->List.Flink = Current;
  685. NewRegion->List.Blink = Current->Blink;
  686. Current->Blink->Flink = &(NewRegion->List);
  687. Current->Blink = &(NewRegion->List);
  688. }
  689. }
  690. else {
  691. //
  692. // If we finished the list of regions then this must be the
  693. // last region.
  694. //
  695. InsertTailList (Current, &(NewRegion->List));
  696. }
  697. return STATUS_SUCCESS;
  698. }
  699. NTSTATUS
  700. AVrfpVsTrackDeleteRegion (
  701. ULONG_PTR Address
  702. )
  703. /*++
  704. Routine description:
  705. This routine deletes a virtual space region from the tracker assuming
  706. there is a region starting exactly as the same address as parameter
  707. `Address'. If there is not an exact match an error is returned.
  708. The function is called with the VS track lock acquired.
  709. Parameters:
  710. Address: start address of the region that must be deleted from the tracker.
  711. Return value:
  712. STATUS_SUCCES if the virtual region has been successfully deleted.
  713. --*/
  714. {
  715. PAVRF_VSPACE_REGION Region;
  716. PLIST_ENTRY Current;
  717. if (AVrfpVsTrackDisabled) {
  718. return STATUS_UNSUCCESSFUL;
  719. }
  720. Current = AVrfpVsTrackList.Flink;
  721. while (Current != &AVrfpVsTrackList) {
  722. Region = CONTAINING_RECORD (Current,
  723. AVRF_VSPACE_REGION,
  724. List);
  725. if (Address >= Region->Address + Region->Size) {
  726. //
  727. // Move on to the next region in the list.
  728. //
  729. Current = Current->Flink;
  730. }
  731. else if (Address >= Region->Address) {
  732. //
  733. // Any region clashing with this one will be deleted.
  734. //
  735. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_SHOW_VSPACE_TRACKING)) {
  736. DbgPrint ("AVRF: deleting virtual space region @ %p (size %p) \n",
  737. Region->Address, Region->Size);
  738. }
  739. AVrfpVsTrackRegionCount -= 1;
  740. AVrfpVsTrackMemoryTotal -= Region->Size;
  741. RemoveEntryList (&(Region->List));
  742. AVrfpFree (Region);
  743. return STATUS_SUCCESS;
  744. }
  745. else {
  746. //
  747. // Virtual space tracker is sorted so there is no chance to find
  748. // a region containing the address any more.
  749. //
  750. break;
  751. }
  752. }
  753. return STATUS_SUCCESS;
  754. }
  755. NTSTATUS
  756. AVrfpGetVadInformation (
  757. PVOID Address,
  758. PVOID * VadAddress,
  759. PSIZE_T VadSize
  760. )
  761. /*++
  762. Routine description:
  763. This routine takes an arbitrary address in a virtual space region
  764. containing private memory and finds out the start address
  765. and size of the VAD containing it.
  766. If the address points into some other type of memory (free, mapped, etc.)
  767. the function will return an error.
  768. The tricky part in the implementation is that a private VAD can have various
  769. portions committed or decommitted so a simple VirtualQuery() will not give
  770. all the information.
  771. Parameters:
  772. Address: arbitrary address.
  773. VadAddress: pointer to variable where start address of the VAD region
  774. will be written.
  775. VadSize: pointer to variable where region size of the VAD will be
  776. written.
  777. Return value:
  778. STATUS_SUCCESS if the VAD contained private memory and the start address
  779. and size have been written.
  780. --*/
  781. {
  782. MEMORY_BASIC_INFORMATION MemoryInfo;
  783. NTSTATUS Status;
  784. //
  785. // Query the size of the allocation.
  786. //
  787. Status = NtQueryVirtualMemory (NtCurrentProcess (),
  788. Address,
  789. MemoryBasicInformation,
  790. &MemoryInfo,
  791. sizeof MemoryInfo,
  792. NULL);
  793. if (! NT_SUCCESS (Status) ) {
  794. //
  795. // For this case only we disable the VS tracker for good.
  796. // We do this so that the process can continue to run even if
  797. // the tracking infrastructure cannot be used any more.
  798. //
  799. AVrfpVsTrackDisabled = TRUE;
  800. return Status;
  801. }
  802. if (MemoryInfo.Type != MEM_PRIVATE) {
  803. return STATUS_NOT_IMPLEMENTED;
  804. }
  805. *VadAddress = MemoryInfo.AllocationBase;
  806. *VadSize = MemoryInfo.RegionSize;
  807. Address = *VadAddress;
  808. do {
  809. Address = (PVOID)((ULONG_PTR)Address + MemoryInfo.RegionSize);
  810. Status = NtQueryVirtualMemory (NtCurrentProcess (),
  811. Address,
  812. MemoryBasicInformation,
  813. &MemoryInfo,
  814. sizeof MemoryInfo,
  815. NULL);
  816. if (! NT_SUCCESS (Status) ) {
  817. //
  818. // For this case only we disable the VS tracker for good.
  819. // We do this so that the process can continue to run even if
  820. // the tracking infrastructure cannot be used any more.
  821. //
  822. AVrfpVsTrackDisabled = TRUE;
  823. return Status;
  824. }
  825. if (*VadAddress == MemoryInfo.AllocationBase) {
  826. *VadSize += MemoryInfo.RegionSize;
  827. }
  828. } while (*VadAddress == MemoryInfo.AllocationBase);
  829. return STATUS_SUCCESS;
  830. }
  831. NTSTATUS
  832. AVrfpVsTrackDeleteRegionContainingAddress (
  833. PVOID Address
  834. )
  835. /*++
  836. Routine description:
  837. This routine takes an arbitrary address and tries to delete the virtual
  838. region containing it from the VS tracker.
  839. If the address points into some other type of memory (free, mapped, etc.)
  840. the function will return an error.
  841. Parameters:
  842. Address: arbitrary address.
  843. Return value:
  844. STATUS_SUCCESS if the virtual region has been deleted.
  845. --*/
  846. {
  847. NTSTATUS Status;
  848. PVOID VadAddress;
  849. SIZE_T VadSize;
  850. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_SPACE_TRACKING) == 0) {
  851. return STATUS_NOT_IMPLEMENTED;
  852. }
  853. if (AVrfpVsTrackDisabled) {
  854. return STATUS_UNSUCCESSFUL;
  855. }
  856. Status = AVrfpGetVadInformation (Address,
  857. &VadAddress,
  858. &VadSize);
  859. if (NT_SUCCESS(Status)) {
  860. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_SHOW_VSPACE_TRACKING)) {
  861. DbgPrint ("AVRF: deleting stack @ %p \n", VadAddress);
  862. }
  863. AVrfpVsTrackerLock ();
  864. AVrfpVsTrackDeleteRegion ((ULONG_PTR)VadAddress);
  865. AVrfpVsTrackerUnlock ();
  866. }
  867. else {
  868. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_SHOW_VSPACE_TRACKING)) {
  869. DbgPrint ("AVRF: failed to find a stack @ %p (%X)\n", VadAddress, Status);
  870. }
  871. }
  872. return Status;
  873. }
  874. /////////////////////////////////////////////////////////////////////
  875. //////////////////////////////////////////////////// IsBadPtr checks
  876. /////////////////////////////////////////////////////////////////////
  877. ULONG
  878. AVrfpProbeMemExceptionFilter (
  879. IN ULONG ExceptionCode,
  880. IN PVOID ExceptionRecord,
  881. IN CONST VOID *Address
  882. )
  883. {
  884. VERIFIER_STOP (APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  885. "unexpected exception raised while probing memory",
  886. ExceptionCode, "Exception code.",
  887. ((PEXCEPTION_POINTERS)ExceptionRecord)->ExceptionRecord, "Exception record. Use .exr to display it.",
  888. ((PEXCEPTION_POINTERS)ExceptionRecord)->ContextRecord, "Context record. Use .cxr to display it.",
  889. Address, "Memory address");
  890. return EXCEPTION_EXECUTE_HANDLER;
  891. }
  892. BOOL
  893. AVrfpVerifyReadAccess (
  894. IN CONST VOID *UserStartAddress,
  895. IN UINT_PTR UserSize,
  896. IN CONST VOID *RegionStartAddress,
  897. OUT PUINT_PTR RegionSize
  898. )
  899. {
  900. PVOID BaseAddress;
  901. BOOL Success;
  902. NTSTATUS Status;
  903. SIZE_T InfoLength;
  904. MEMORY_BASIC_INFORMATION MemoryInformation;
  905. //
  906. // Assume success and block size == page size.
  907. // We will simply return these values in case NtQueryVirtualMemory fails
  908. // because that could happen in low memory conditions, etc.
  909. //
  910. Success = TRUE;
  911. *RegionSize = AVrfpSysBasicInfo.PageSize;
  912. BaseAddress = PAGE_ALIGN (RegionStartAddress);
  913. //
  914. // Sanity check for the based address.
  915. //
  916. if (AVrfpSysBasicInfo.MaximumUserModeAddress <= (ULONG_PTR)BaseAddress) {
  917. VERIFIER_STOP (APPLICATION_VERIFIER_PROBE_INVALID_ADDRESS | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  918. "Probing invalid address",
  919. UserStartAddress, "Start address",
  920. UserSize, "Memory block size",
  921. BaseAddress, "Invalid address",
  922. NULL, "" );
  923. Success = FALSE;
  924. }
  925. else {
  926. //
  927. // Query the size of the allocation and verify that the memory
  928. // is not free already.
  929. //
  930. Status = NtQueryVirtualMemory (NtCurrentProcess (),
  931. BaseAddress,
  932. MemoryBasicInformation,
  933. &MemoryInformation,
  934. sizeof (MemoryInformation),
  935. &InfoLength);
  936. if (NT_SUCCESS (Status)) {
  937. if (MemoryInformation.State & MEM_FREE) {
  938. //
  939. // Probing free memory!
  940. //
  941. VERIFIER_STOP (APPLICATION_VERIFIER_PROBE_FREE_MEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  942. "Probing free memory",
  943. UserStartAddress, "Start address",
  944. UserSize, "Memory block size",
  945. BaseAddress, "Address of free memory page",
  946. NULL, "" );
  947. Success = FALSE;
  948. }
  949. else if (MemoryInformation.AllocationProtect & PAGE_GUARD) {
  950. //
  951. // Probing a guard page, probably part of a stack!
  952. //
  953. VERIFIER_STOP (APPLICATION_VERIFIER_PROBE_GUARD_PAGE | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  954. "Probing guard page",
  955. UserStartAddress, "Start address",
  956. UserSize, "Memory block size",
  957. BaseAddress, "Address of guard page",
  958. NULL, "" );
  959. Success = FALSE;
  960. }
  961. else {
  962. //
  963. // Everything seems to be OK. Return to the caller the number of bytes
  964. // to skip up to the next memory region.
  965. //
  966. ASSERT ((MemoryInformation.RegionSize % AVrfpSysBasicInfo.PageSize) == 0);
  967. *RegionSize = MemoryInformation.RegionSize;
  968. }
  969. }
  970. }
  971. return Success;
  972. }
  973. BOOL
  974. AVrfpProbeMemoryBlockChecks (
  975. IN CONST VOID *UserBaseAddress,
  976. IN UINT_PTR UserSize
  977. )
  978. {
  979. PBYTE EndAddress;
  980. PBYTE StartAddress;
  981. ULONG PageSize;
  982. BOOL Success;
  983. UINT_PTR RegionSize;
  984. Success = TRUE;
  985. PageSize = AVrfpSysBasicInfo.PageSize;
  986. //
  987. // If the structure has zero length, then there is nothing to probe.
  988. //
  989. if (UserSize != 0) {
  990. if (UserBaseAddress == NULL) {
  991. VERIFIER_STOP (APPLICATION_VERIFIER_PROBE_NULL | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  992. "Probing NULL address",
  993. NULL, "",
  994. NULL, "",
  995. NULL, "",
  996. NULL, "" );
  997. Success = FALSE;
  998. }
  999. else {
  1000. StartAddress = (PBYTE)UserBaseAddress;
  1001. EndAddress = StartAddress + UserSize - 1;
  1002. if (EndAddress < StartAddress) {
  1003. VERIFIER_STOP (APPLICATION_VERIFIER_PROBE_INVALID_START_OR_SIZE | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1004. "Probing memory block with invalid start address or size",
  1005. StartAddress, "Start address",
  1006. UserSize, "Memory block size",
  1007. NULL, "",
  1008. NULL, "" );
  1009. Success = FALSE;
  1010. }
  1011. else {
  1012. //
  1013. // Truncate the start and end to page size alignment
  1014. // and verify every page in this memory block.
  1015. //
  1016. StartAddress = PAGE_ALIGN (StartAddress);
  1017. EndAddress = PAGE_ALIGN (EndAddress);
  1018. while (StartAddress <= EndAddress) {
  1019. Success = AVrfpVerifyReadAccess (UserBaseAddress,
  1020. UserSize,
  1021. StartAddress,
  1022. &RegionSize);
  1023. if (Success != FALSE) {
  1024. ASSERT ((RegionSize % PageSize) == 0);
  1025. if (RegionSize <= (UINT_PTR)(EndAddress - StartAddress)) {
  1026. StartAddress = StartAddress + RegionSize;
  1027. }
  1028. else {
  1029. StartAddress = StartAddress + PageSize;
  1030. }
  1031. }
  1032. else {
  1033. //
  1034. // We have detected a problem already - bail out.
  1035. //
  1036. break;
  1037. }
  1038. }
  1039. }
  1040. }
  1041. }
  1042. return Success;
  1043. }
  1044. //WINBASEAPI
  1045. BOOL
  1046. WINAPI
  1047. AVrfpIsBadReadPtr(
  1048. CONST VOID *lp,
  1049. UINT_PTR cb
  1050. )
  1051. {
  1052. typedef BOOL (WINAPI * FUNCTION_TYPE) (CONST VOID *, UINT_PTR);
  1053. FUNCTION_TYPE Function;
  1054. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1055. AVrfpProbeMemoryBlockChecks (lp,
  1056. cb);
  1057. }
  1058. //
  1059. // Call the original funtion.
  1060. //
  1061. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1062. AVRF_INDEX_KERNEL32_ISBADREADPTR);
  1063. return (*Function) (lp, cb);
  1064. }
  1065. //WINBASEAPI
  1066. BOOL
  1067. WINAPI
  1068. AVrfpIsBadHugeReadPtr(
  1069. CONST VOID *lp,
  1070. UINT_PTR cb
  1071. )
  1072. {
  1073. typedef BOOL (WINAPI * FUNCTION_TYPE) (CONST VOID *, UINT_PTR);
  1074. FUNCTION_TYPE Function;
  1075. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1076. AVrfpProbeMemoryBlockChecks (lp,
  1077. cb);
  1078. }
  1079. //
  1080. // Call the original funtion.
  1081. //
  1082. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1083. AVRF_INDEX_KERNEL32_ISBADHUGEREADPTR);
  1084. return (*Function) (lp, cb);
  1085. }
  1086. //WINBASEAPI
  1087. BOOL
  1088. WINAPI
  1089. AVrfpIsBadWritePtr(
  1090. LPVOID lp,
  1091. UINT_PTR cb
  1092. )
  1093. {
  1094. typedef BOOL (WINAPI * FUNCTION_TYPE) (LPVOID , UINT_PTR);
  1095. FUNCTION_TYPE Function;
  1096. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1097. AVrfpProbeMemoryBlockChecks (lp,
  1098. cb);
  1099. }
  1100. //
  1101. // Call the original funtion.
  1102. //
  1103. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1104. AVRF_INDEX_KERNEL32_ISBADWRITEPTR);
  1105. return (*Function) (lp, cb);
  1106. }
  1107. //WINBASEAPI
  1108. BOOL
  1109. WINAPI
  1110. AVrfpIsBadHugeWritePtr(
  1111. LPVOID lp,
  1112. UINT_PTR cb
  1113. )
  1114. {
  1115. typedef BOOL (WINAPI * FUNCTION_TYPE) (LPVOID , UINT_PTR);
  1116. FUNCTION_TYPE Function;
  1117. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1118. AVrfpProbeMemoryBlockChecks (lp,
  1119. cb);
  1120. }
  1121. //
  1122. // Call the original funtion.
  1123. //
  1124. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1125. AVRF_INDEX_KERNEL32_ISBADHUGEWRITEPTR);
  1126. return (*Function) (lp, cb);
  1127. }
  1128. //WINBASEAPI
  1129. BOOL
  1130. WINAPI
  1131. AVrfpIsBadCodePtr(
  1132. FARPROC lpfn
  1133. )
  1134. {
  1135. typedef BOOL (WINAPI * FUNCTION_TYPE) (FARPROC);
  1136. FUNCTION_TYPE Function;
  1137. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1138. AVrfpProbeMemoryBlockChecks (lpfn,
  1139. 1);
  1140. }
  1141. //
  1142. // Call the original funtion.
  1143. //
  1144. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1145. AVRF_INDEX_KERNEL32_ISBADCODEPTR);
  1146. return (*Function) (lpfn);
  1147. }
  1148. //WINBASEAPI
  1149. BOOL
  1150. WINAPI
  1151. AVrfpIsBadStringPtrA(
  1152. LPCSTR lpsz,
  1153. UINT_PTR cchMax
  1154. )
  1155. {
  1156. typedef BOOL (WINAPI * FUNCTION_TYPE) (LPCSTR , UINT_PTR);
  1157. FUNCTION_TYPE Function;
  1158. ULONG PageSize;
  1159. BOOL FoundNull;
  1160. BOOL Success;
  1161. LPCSTR StartAddress;
  1162. LPCSTR EndAddress;
  1163. CHAR Character;
  1164. PageSize = AVrfpSysBasicInfo.PageSize;
  1165. FoundNull = FALSE;
  1166. StartAddress = lpsz;
  1167. EndAddress = lpsz + cchMax - 1;
  1168. while (StartAddress <= EndAddress && FoundNull == FALSE) {
  1169. //
  1170. // Verify read access to the current page.
  1171. //
  1172. Success = AVrfpProbeMemoryBlockChecks (StartAddress,
  1173. sizeof (CHAR));
  1174. if (Success == FALSE) {
  1175. //
  1176. // We have detected a problem already - bail out.
  1177. //
  1178. break;
  1179. }
  1180. else {
  1181. //
  1182. // Skip all the bytes up to the next page
  1183. // or the NULL string terminator.
  1184. //
  1185. while (TRUE) {
  1186. //
  1187. // Read the currect character, while protecting
  1188. // ourselves against a possible exception (alignment, etc).
  1189. //
  1190. try {
  1191. Character = *StartAddress;
  1192. }
  1193. except (AVrfpProbeMemExceptionFilter (_exception_code(), _exception_info(), StartAddress)) {
  1194. //
  1195. // We have detected a problem already - bail out.
  1196. //
  1197. goto Done;
  1198. }
  1199. //
  1200. // If we have found the NULL terminator we are done.
  1201. //
  1202. if (Character == 0) {
  1203. FoundNull = TRUE;
  1204. break;
  1205. }
  1206. //
  1207. // Go to the next character. If that is at the beginning
  1208. // of a new page we have to check it's attributes.
  1209. //
  1210. StartAddress += 1;
  1211. if (StartAddress > EndAddress) {
  1212. //
  1213. // We have reached the max length of the buffer.
  1214. //
  1215. break;
  1216. }
  1217. if (((ULONG_PTR)StartAddress % PageSize) < sizeof (CHAR)) {
  1218. //
  1219. // New page.
  1220. //
  1221. break;
  1222. }
  1223. }
  1224. }
  1225. }
  1226. Done:
  1227. //
  1228. // Call the original funtion.
  1229. //
  1230. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1231. AVRF_INDEX_KERNEL32_ISBADSTRINGPTRA);
  1232. return (*Function) (lpsz, cchMax);
  1233. }
  1234. //WINBASEAPI
  1235. BOOL
  1236. WINAPI
  1237. AVrfpIsBadStringPtrW(
  1238. LPCWSTR lpsz,
  1239. UINT_PTR cchMax
  1240. )
  1241. {
  1242. typedef BOOL (WINAPI * FUNCTION_TYPE) (LPCWSTR , UINT_PTR);
  1243. FUNCTION_TYPE Function;
  1244. ULONG PageSize;
  1245. BOOL FoundNull;
  1246. BOOL Success;
  1247. LPCWSTR StartAddress;
  1248. LPCWSTR EndAddress;
  1249. WCHAR Character;
  1250. PageSize = AVrfpSysBasicInfo.PageSize;
  1251. FoundNull = FALSE;
  1252. StartAddress = lpsz;
  1253. EndAddress = lpsz + cchMax - 1;
  1254. while (StartAddress <= EndAddress && FoundNull == FALSE) {
  1255. //
  1256. // Verify read access to the current page.
  1257. //
  1258. Success = AVrfpProbeMemoryBlockChecks (StartAddress,
  1259. sizeof (WCHAR));
  1260. if (Success == FALSE) {
  1261. //
  1262. // We have detected a problem already - bail out.
  1263. //
  1264. break;
  1265. }
  1266. else {
  1267. //
  1268. // Skip all the bytes up to the next page
  1269. // or the NULL string terminator.
  1270. //
  1271. while (TRUE) {
  1272. //
  1273. // Read the currect character, while protecting
  1274. // ourselves against a possible exception (alignment, etc).
  1275. //
  1276. try {
  1277. Character = *StartAddress;
  1278. }
  1279. except (AVrfpProbeMemExceptionFilter (_exception_code(), _exception_info(), StartAddress)) {
  1280. //
  1281. // We have detected a problem already - bail out.
  1282. //
  1283. goto Done;
  1284. }
  1285. //
  1286. // If we have found the NULL terminator we are done.
  1287. //
  1288. if (Character == 0) {
  1289. FoundNull = TRUE;
  1290. break;
  1291. }
  1292. //
  1293. // Go to the next character. If that is at the beginning
  1294. // of a new page we have to check it's attributes.
  1295. //
  1296. StartAddress += 1;
  1297. if (StartAddress > EndAddress) {
  1298. //
  1299. // We have reached the max length of the buffer.
  1300. //
  1301. break;
  1302. }
  1303. if (((ULONG_PTR)StartAddress % PageSize) < sizeof (WCHAR)) {
  1304. //
  1305. // New page.
  1306. //
  1307. break;
  1308. }
  1309. }
  1310. }
  1311. }
  1312. Done:
  1313. //
  1314. // Call the original funtion.
  1315. //
  1316. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1317. AVRF_INDEX_KERNEL32_ISBADSTRINGPTRW);
  1318. return (*Function) (lpsz, cchMax);
  1319. }
  1320. /////////////////////////////////////////////////////////////////////
  1321. /////////////////////////////////////////// VirtualFree sanity checks
  1322. /////////////////////////////////////////////////////////////////////
  1323. VOID
  1324. AVrfVirtualFreeSanityChecks (
  1325. IN SIZE_T dwSize,
  1326. IN DWORD dwFreeType
  1327. )
  1328. {
  1329. //
  1330. // The Win32 layer only allows MEM_RELEASE with Size == 0.
  1331. //
  1332. if (dwFreeType == MEM_RELEASE && dwSize != 0) {
  1333. VERIFIER_STOP (APPLICATION_VERIFIER_INVALID_FREEMEM | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1334. "Incorrect Size parameter for VirtualFree (MEM_RELEASE) operation",
  1335. dwSize, "Incorrect size used by the application",
  1336. 0, "Expected correct size",
  1337. NULL, "",
  1338. NULL, "" );
  1339. }
  1340. }
  1341. //WINBASEAPI
  1342. BOOL
  1343. WINAPI
  1344. AVrfpVirtualFree(
  1345. IN LPVOID lpAddress,
  1346. IN SIZE_T dwSize,
  1347. IN DWORD dwFreeType
  1348. )
  1349. {
  1350. typedef BOOL (WINAPI * FUNCTION_TYPE) (LPVOID , SIZE_T, DWORD);
  1351. FUNCTION_TYPE Function;
  1352. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1353. AVrfVirtualFreeSanityChecks (dwSize, dwFreeType);
  1354. }
  1355. //
  1356. // Call the original funtion.
  1357. //
  1358. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1359. AVRF_INDEX_KERNEL32_VIRTUALFREE);
  1360. return (*Function) (lpAddress, dwSize, dwFreeType);
  1361. }
  1362. //WINBASEAPI
  1363. BOOL
  1364. WINAPI
  1365. AVrfpVirtualFreeEx(
  1366. IN HANDLE hProcess,
  1367. IN LPVOID lpAddress,
  1368. IN SIZE_T dwSize,
  1369. IN DWORD dwFreeType
  1370. )
  1371. {
  1372. typedef BOOL (WINAPI * FUNCTION_TYPE) (HANDLE, LPVOID , SIZE_T, DWORD);
  1373. FUNCTION_TYPE Function;
  1374. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_VIRTUAL_MEM_CHECKS) != 0) {
  1375. AVrfVirtualFreeSanityChecks (dwSize, dwFreeType);
  1376. }
  1377. //
  1378. // Call the original funtion.
  1379. //
  1380. Function = AVRFP_GET_ORIGINAL_EXPORT (AVrfpKernel32Thunks,
  1381. AVRF_INDEX_KERNEL32_VIRTUALFREEEX);
  1382. return (*Function) (hProcess, lpAddress, dwSize, dwFreeType);
  1383. }