2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/virtual.c
5 * PURPOSE: Implementing operations on virtual memory.
7 * PROGRAMMERS: David Welch
10 /* INCLUDE ********************************************************************/
16 #define MI_MAPPED_COPY_PAGES 16
17 #define MI_POOL_COPY_BYTES 512
18 #define MI_MAX_TRANSFER_SIZE 64 * 1024
21 /* PRIVATE FUNCTIONS **********************************************************/
24 MiGetExceptionInfo(EXCEPTION_POINTERS
*ExceptionInfo
, BOOLEAN
* HaveBadAddress
, ULONG_PTR
* BadAddress
)
26 PEXCEPTION_RECORD ExceptionRecord
;
30 *HaveBadAddress
= FALSE
;
32 /* Get the exception record */
33 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
35 /* Look at the exception code */
36 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
37 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
38 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
40 /* We can tell the address if we have more than one parameter */
41 if (ExceptionRecord
->NumberParameters
> 1)
43 /* Return the address */
44 *HaveBadAddress
= TRUE
;
45 *BadAddress
= ExceptionRecord
->ExceptionInformation
[1];
49 /* Continue executing the next handler */
50 return EXCEPTION_EXECUTE_HANDLER
;
55 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
56 IN PVOID SourceAddress
,
57 IN PEPROCESS TargetProcess
,
58 OUT PVOID TargetAddress
,
60 IN KPROCESSOR_MODE PreviousMode
,
61 OUT PSIZE_T ReturnSize
)
63 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
64 PMDL Mdl
= (PMDL
)MdlBuffer
;
65 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
66 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
67 volatile BOOLEAN PagesLocked
;
68 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
69 volatile PVOID MdlAddress
;
71 BOOLEAN HaveBadAddress
;
75 /* Calculate the maximum amount of data to move */
76 TotalSize
= (MI_MAPPED_COPY_PAGES
- 2) * PAGE_SIZE
;
77 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
78 CurrentSize
= TotalSize
;
79 RemainingSize
= BufferSize
;
81 /* Loop as long as there is still data */
82 while (RemainingSize
> 0)
84 /* Check if this transfer will finish everything off */
85 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
87 /* Attach to the source address space */
88 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
90 /* Reset state for this pass */
93 FailedInMoving
= FALSE
;
94 ASSERT(FailedInProbe
== FALSE
);
96 /* Protect user-mode copy */
99 /* If this is our first time, probe the buffer */
100 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
102 /* Catch a failure here */
103 FailedInProbe
= TRUE
;
106 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
109 FailedInProbe
= FALSE
;
112 /* Initialize and probe and lock the MDL */
113 MmInitializeMdl (Mdl
, CurrentAddress
, CurrentSize
);
114 MmProbeAndLockPages (Mdl
, PreviousMode
, IoReadAccess
);
117 /* Now map the pages */
118 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
126 /* Use our SEH handler to pick this up */
127 FailedInMapping
= TRUE
;
128 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
131 /* Now let go of the source and grab to the target process */
132 KeUnstackDetachProcess(&ApcState
);
133 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
135 /* Check if this is our first time through */
136 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
138 /* Catch a failure here */
139 FailedInProbe
= TRUE
;
142 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
145 FailedInProbe
= FALSE
;
148 /* Now do the actual move */
149 FailedInMoving
= TRUE
;
150 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
152 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
154 /* Detach from whoever we may be attached to */
155 KeUnstackDetachProcess(&ApcState
);
157 /* Check if we had mapped the pages */
158 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
160 /* Check if we had locked the pages */
161 if (PagesLocked
) MmUnlockPages(Mdl
);
163 /* Check if we failed during the probe or mapping */
164 if ((FailedInProbe
) || (FailedInMapping
))
167 _SEH2_YIELD(return _SEH2_GetExceptionCode());
170 /* Otherwise, we failed probably during the move */
171 *ReturnSize
= BufferSize
- RemainingSize
;
174 /* Check if we know exactly where we stopped copying */
177 /* Return the exact number of bytes copied */
178 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
182 /* Return partial copy */
183 _SEH2_YIELD(return STATUS_PARTIAL_COPY
);
187 /* Detach from target */
188 KeUnstackDetachProcess(&ApcState
);
190 /* Unmap and unlock */
191 MmUnmapLockedPages(MdlAddress
, Mdl
);
194 /* Update location and size */
195 RemainingSize
-= CurrentSize
;
196 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
197 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
201 *ReturnSize
= BufferSize
;
202 return STATUS_SUCCESS
;
207 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
208 IN PVOID SourceAddress
,
209 IN PEPROCESS TargetProcess
,
210 OUT PVOID TargetAddress
,
211 IN SIZE_T BufferSize
,
212 IN KPROCESSOR_MODE PreviousMode
,
213 OUT PSIZE_T ReturnSize
)
215 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
216 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
217 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
218 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
221 BOOLEAN HaveBadAddress
;
222 ULONG_PTR BadAddress
;
225 /* Calculate the maximum amount of data to move */
226 TotalSize
= MI_MAX_TRANSFER_SIZE
;
227 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
228 CurrentSize
= TotalSize
;
229 RemainingSize
= BufferSize
;
231 /* Check if we can use the stack */
232 if (BufferSize
<= MI_POOL_COPY_BYTES
)
235 PoolAddress
= (PVOID
)StackBuffer
;
240 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, TAG_VM
);
241 if (!PoolAddress
) ASSERT(FALSE
);
242 HavePoolAddress
= TRUE
;
245 /* Loop as long as there is still data */
246 while (RemainingSize
> 0)
248 /* Check if this transfer will finish everything off */
249 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
251 /* Attach to the source address space */
252 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
254 /* Reset state for this pass */
255 FailedInMoving
= FALSE
;
256 ASSERT(FailedInProbe
== FALSE
);
258 /* Protect user-mode copy */
261 /* If this is our first time, probe the buffer */
262 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
264 /* Catch a failure here */
265 FailedInProbe
= TRUE
;
268 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
271 FailedInProbe
= FALSE
;
275 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
277 /* Now let go of the source and grab to the target process */
278 KeUnstackDetachProcess(&ApcState
);
279 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
281 /* Check if this is our first time through */
282 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
284 /* Catch a failure here */
285 FailedInProbe
= TRUE
;
288 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
291 FailedInProbe
= FALSE
;
294 /* Now do the actual move */
295 FailedInMoving
= TRUE
;
296 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
298 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
300 /* Detach from whoever we may be attached to */
301 KeUnstackDetachProcess(&ApcState
);
303 /* Check if we had allocated pool */
304 if (HavePoolAddress
) ExFreePool(PoolAddress
);
306 /* Check if we failed during the probe */
310 _SEH2_YIELD(return _SEH2_GetExceptionCode());
313 /* Otherwise, we failed probably during the move */
314 *ReturnSize
= BufferSize
- RemainingSize
;
317 /* Check if we know exactly where we stopped copying */
320 /* Return the exact number of bytes copied */
321 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
325 /* Return partial copy */
326 _SEH2_YIELD(return STATUS_PARTIAL_COPY
);
330 /* Detach from target */
331 KeUnstackDetachProcess(&ApcState
);
333 /* Update location and size */
334 RemainingSize
-= CurrentSize
;
335 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
336 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
339 /* Check if we had allocated pool */
340 if (HavePoolAddress
) ExFreePool(PoolAddress
);
343 *ReturnSize
= BufferSize
;
344 return STATUS_SUCCESS
;
349 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
350 IN PVOID SourceAddress
,
351 IN PEPROCESS TargetProcess
,
352 OUT PVOID TargetAddress
,
353 IN SIZE_T BufferSize
,
354 IN KPROCESSOR_MODE PreviousMode
,
355 OUT PSIZE_T ReturnSize
)
358 PEPROCESS Process
= SourceProcess
;
360 /* Don't accept zero-sized buffers */
361 if (!BufferSize
) return STATUS_SUCCESS
;
363 /* If we are copying from ourselves, lock the target instead */
364 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
366 /* Acquire rundown protection */
367 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
370 return STATUS_PROCESS_IS_TERMINATING
;
373 /* See if we should use the pool copy */
374 if (BufferSize
> MI_POOL_COPY_BYTES
)
377 Status
= MiDoMappedCopy(SourceProcess
,
388 Status
= MiDoPoolCopy(SourceProcess
,
397 /* Release the lock */
398 ExReleaseRundownProtection(&Process
->RundownProtect
);
403 MiQueryVirtualMemory(IN HANDLE ProcessHandle
,
405 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
406 OUT PVOID VirtualMemoryInformation
,
408 OUT PSIZE_T ResultLength
)
412 MEMORY_AREA
* MemoryArea
;
413 PMMSUPPORT AddressSpace
;
415 Status
= ObReferenceObjectByHandle(ProcessHandle
,
416 PROCESS_QUERY_INFORMATION
,
422 if (!NT_SUCCESS(Status
))
424 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
428 AddressSpace
= &Process
->Vm
;
430 MmLockAddressSpace(AddressSpace
);
431 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
432 switch(VirtualMemoryInformationClass
)
434 case MemoryBasicInformation
:
436 PMEMORY_BASIC_INFORMATION Info
=
437 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
438 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
440 MmUnlockAddressSpace(AddressSpace
);
441 ObDereferenceObject(Process
);
442 return(STATUS_INFO_LENGTH_MISMATCH
);
445 if (MemoryArea
== NULL
)
448 Info
->State
= MEM_FREE
;
449 Info
->Protect
= PAGE_NOACCESS
;
450 Info
->AllocationProtect
= 0;
451 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
452 Info
->AllocationBase
= NULL
;
453 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
454 Status
= STATUS_SUCCESS
;
455 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
459 switch(MemoryArea
->Type
)
461 case MEMORY_AREA_VIRTUAL_MEMORY
:
462 case MEMORY_AREA_PEB_OR_TEB
:
463 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
467 case MEMORY_AREA_SECTION_VIEW
:
468 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
472 case MEMORY_AREA_NO_ACCESS
:
473 Info
->Type
= MEM_PRIVATE
;
474 Info
->State
= MEM_RESERVE
;
475 Info
->Protect
= MemoryArea
->Protect
;
476 Info
->AllocationProtect
= MemoryArea
->Protect
;
477 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
478 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
479 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
480 (ULONG_PTR
)MemoryArea
->StartingAddress
;
481 Status
= STATUS_SUCCESS
;
482 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
485 case MEMORY_AREA_SHARED_DATA
:
486 Info
->Type
= MEM_PRIVATE
;
487 Info
->State
= MEM_COMMIT
;
488 Info
->Protect
= MemoryArea
->Protect
;
489 Info
->AllocationProtect
= MemoryArea
->Protect
;
490 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
491 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
492 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
493 (ULONG_PTR
)MemoryArea
->StartingAddress
;
494 Status
= STATUS_SUCCESS
;
495 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
498 case MEMORY_AREA_SYSTEM
:
500 Info
->State
= MEM_COMMIT
;
501 Info
->Protect
= MemoryArea
->Protect
;
502 Info
->AllocationProtect
= MemoryArea
->Protect
;
503 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
504 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
505 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
506 (ULONG_PTR
)MemoryArea
->StartingAddress
;
507 Status
= STATUS_SUCCESS
;
508 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
511 case MEMORY_AREA_KERNEL_STACK
:
513 Info
->State
= MEM_COMMIT
;
514 Info
->Protect
= MemoryArea
->Protect
;
515 Info
->AllocationProtect
= MemoryArea
->Protect
;
516 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
517 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
518 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
519 (ULONG_PTR
)MemoryArea
->StartingAddress
;
520 Status
= STATUS_SUCCESS
;
521 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
524 case MEMORY_AREA_PAGED_POOL
:
526 Info
->State
= MEM_COMMIT
;
527 Info
->Protect
= MemoryArea
->Protect
;
528 Info
->AllocationProtect
= MemoryArea
->Protect
;
529 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
530 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
531 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
532 (ULONG_PTR
)MemoryArea
->StartingAddress
;
533 Status
= STATUS_SUCCESS
;
534 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
538 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
539 Status
= STATUS_UNSUCCESSFUL
;
548 DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass
);
549 Status
= STATUS_INVALID_INFO_CLASS
;
555 MmUnlockAddressSpace(AddressSpace
);
556 ObDereferenceObject(Process
);
562 MiProtectVirtualMemory(IN PEPROCESS Process
,
563 IN OUT PVOID
*BaseAddress
,
564 IN OUT PSIZE_T NumberOfBytesToProtect
,
565 IN ULONG NewAccessProtection
,
566 OUT PULONG OldAccessProtection OPTIONAL
)
568 PMEMORY_AREA MemoryArea
;
569 PMMSUPPORT AddressSpace
;
570 ULONG OldAccessProtection_
;
573 *NumberOfBytesToProtect
=
574 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
575 PAGE_ROUND_DOWN(*BaseAddress
);
576 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
578 AddressSpace
= &Process
->Vm
;
580 MmLockAddressSpace(AddressSpace
);
581 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
582 if (MemoryArea
== NULL
)
584 MmUnlockAddressSpace(AddressSpace
);
585 return STATUS_UNSUCCESSFUL
;
588 if (OldAccessProtection
== NULL
)
589 OldAccessProtection
= &OldAccessProtection_
;
591 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
593 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
594 *NumberOfBytesToProtect
, NewAccessProtection
,
595 OldAccessProtection
);
597 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
599 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
600 *NumberOfBytesToProtect
,
602 OldAccessProtection
);
606 /* FIXME: Should we return failure or success in this case? */
607 Status
= STATUS_CONFLICTING_ADDRESSES
;
610 MmUnlockAddressSpace(AddressSpace
);
617 MiMapLockedPagesInUserSpace(IN PMDL Mdl
,
619 IN MEMORY_CACHING_TYPE CacheType
,
620 IN PVOID BaseAddress
)
623 PPFN_NUMBER MdlPages
;
625 PEPROCESS CurrentProcess
;
629 LARGE_INTEGER BoundaryAddressMultiple
;
631 /* Calculate the number of pages required. */
632 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
633 PageCount
= PAGE_ROUND_UP(Mdl
->ByteCount
+ Mdl
->ByteOffset
) / PAGE_SIZE
;
635 /* Set default page protection */
636 Protect
= PAGE_READWRITE
;
637 if (CacheType
== MmNonCached
) Protect
|= PAGE_NOCACHE
;
639 BoundaryAddressMultiple
.QuadPart
= 0;
642 CurrentProcess
= PsGetCurrentProcess();
644 MmLockAddressSpace(&CurrentProcess
->Vm
);
645 Status
= MmCreateMemoryArea(&CurrentProcess
->Vm
,
646 MEMORY_AREA_MDL_MAPPING
,
648 PageCount
* PAGE_SIZE
,
653 BoundaryAddressMultiple
);
654 MmUnlockAddressSpace(&CurrentProcess
->Vm
);
655 if (!NT_SUCCESS(Status
))
657 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
)
662 /* Throw exception */
663 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
667 /* Set the virtual mappings for the MDL pages. */
668 if (Mdl
->MdlFlags
& MDL_IO_SPACE
)
671 Status
= MmCreateVirtualMappingUnsafe(CurrentProcess
,
680 Status
= MmCreateVirtualMapping(CurrentProcess
,
687 /* Check if the mapping suceeded */
688 if (!NT_SUCCESS(Status
))
690 /* If it can fail, return NULL */
691 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
) return NULL
;
693 /* Throw exception */
694 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
697 /* Return the base */
698 Base
= (PVOID
)((ULONG_PTR
)Base
+ Mdl
->ByteOffset
);
704 MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress
,
707 PMEMORY_AREA MemoryArea
;
710 ASSERT(Mdl
->Process
== PsGetCurrentProcess());
712 /* Find the memory area */
713 MemoryArea
= MmLocateMemoryAreaByAddress(&Mdl
->Process
->Vm
,
718 MmFreeMemoryArea(&Mdl
->Process
->Vm
,
724 /* PUBLIC FUNCTIONS ***********************************************************/
731 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
742 MmSecureVirtualMemory(IN PVOID Address
,
755 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
760 /* SYSTEM CALLS ***************************************************************/
764 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
765 IN PVOID BaseAddress
,
767 IN SIZE_T NumberOfBytesToRead
,
768 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
770 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
773 SIZE_T BytesRead
= 0;
776 /* Check if we came from user mode */
777 if (PreviousMode
!= KernelMode
)
779 /* Validate the read addresses */
780 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
781 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
782 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
783 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
785 /* Don't allow to write into kernel space */
786 return STATUS_ACCESS_VIOLATION
;
789 /* Enter SEH for probe */
792 /* Probe the output value */
793 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
795 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
797 /* Return the exception code */
798 _SEH2_YIELD(return _SEH2_GetExceptionCode());
803 /* Reference the process */
804 Status
= ObReferenceObjectByHandle(ProcessHandle
,
810 if (NT_SUCCESS(Status
))
813 Status
= MmCopyVirtualMemory(Process
,
815 PsGetCurrentProcess(),
821 /* Dereference the process */
822 ObDereferenceObject(Process
);
825 /* Check if the caller sent this parameter */
826 if (NumberOfBytesRead
)
828 /* Enter SEH to guard write */
831 /* Return the number of bytes read */
832 *NumberOfBytesRead
= BytesRead
;
834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
836 /* Handle exception */
837 Status
= _SEH2_GetExceptionCode();
848 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
849 IN PVOID BaseAddress
,
851 IN SIZE_T NumberOfBytesToWrite
,
852 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
854 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
857 SIZE_T BytesWritten
= 0;
860 /* Check if we came from user mode */
861 if (PreviousMode
!= KernelMode
)
863 /* Validate the read addresses */
864 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
865 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
866 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
867 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
869 /* Don't allow to write into kernel space */
870 return STATUS_ACCESS_VIOLATION
;
873 /* Enter SEH for probe */
876 /* Probe the output value */
877 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
879 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
881 /* Return the exception code */
882 _SEH2_YIELD(return _SEH2_GetExceptionCode());
887 /* Reference the process */
888 Status
= ObReferenceObjectByHandle(ProcessHandle
,
894 if (NT_SUCCESS(Status
))
897 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
901 NumberOfBytesToWrite
,
905 /* Dereference the process */
906 ObDereferenceObject(Process
);
909 /* Check if the caller sent this parameter */
910 if (NumberOfBytesWritten
)
912 /* Enter SEH to guard write */
915 /* Return the number of bytes read */
916 *NumberOfBytesWritten
= BytesWritten
;
918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
920 /* Handle exception */
921 Status
= _SEH2_GetExceptionCode();
932 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
933 IN OUT PVOID
*UnsafeBaseAddress
,
934 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
935 IN ULONG NewAccessProtection
,
936 OUT PULONG UnsafeOldAccessProtection
)
939 ULONG OldAccessProtection
;
941 PVOID BaseAddress
= NULL
;
942 SIZE_T NumberOfBytesToProtect
= 0;
943 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
947 /* Check for valid protection flags */
948 Protection
= NewAccessProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
949 if (Protection
!= PAGE_NOACCESS
&&
950 Protection
!= PAGE_READONLY
&&
951 Protection
!= PAGE_READWRITE
&&
952 Protection
!= PAGE_WRITECOPY
&&
953 Protection
!= PAGE_EXECUTE
&&
954 Protection
!= PAGE_EXECUTE_READ
&&
955 Protection
!= PAGE_EXECUTE_READWRITE
&&
956 Protection
!= PAGE_EXECUTE_WRITECOPY
)
958 return STATUS_INVALID_PAGE_PROTECTION
;
961 /* Check if we came from user mode */
962 if (PreviousMode
!= KernelMode
)
964 /* Enter SEH for probing */
967 /* Validate all outputs */
968 ProbeForWritePointer(UnsafeBaseAddress
);
969 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
970 ProbeForWriteUlong(UnsafeOldAccessProtection
);
973 BaseAddress
= *UnsafeBaseAddress
;
974 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
978 /* Return the exception code */
979 _SEH2_YIELD(return _SEH2_GetExceptionCode());
985 /* Capture directly */
986 BaseAddress
= *UnsafeBaseAddress
;
987 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
990 /* Catch illegal base address */
991 if (BaseAddress
> (PVOID
)MmUserProbeAddress
) return STATUS_INVALID_PARAMETER_2
;
993 /* Catch illegal region size */
994 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
997 return STATUS_INVALID_PARAMETER_3
;
1000 /* 0 is also illegal */
1001 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
1003 /* Get a reference to the process */
1004 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1005 PROCESS_VM_OPERATION
,
1010 if (!NT_SUCCESS(Status
)) return Status
;
1012 /* Do the actual work */
1013 Status
= MiProtectVirtualMemory(Process
,
1015 &NumberOfBytesToProtect
,
1016 NewAccessProtection
,
1017 &OldAccessProtection
);
1019 /* Release reference */
1020 ObDereferenceObject(Process
);
1022 /* Enter SEH to return data */
1025 /* Return data to user */
1026 *UnsafeOldAccessProtection
= OldAccessProtection
;
1027 *UnsafeBaseAddress
= BaseAddress
;
1028 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1032 /* Catch exception */
1033 Status
= _SEH2_GetExceptionCode();
1042 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
1044 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
1045 OUT PVOID VirtualMemoryInformation
,
1047 OUT PSIZE_T UnsafeResultLength
)
1050 SIZE_T ResultLength
= 0;
1051 KPROCESSOR_MODE PreviousMode
;
1052 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
1053 UNICODE_STRING ModuleFileName
;
1054 PMEMORY_SECTION_NAME SectionName
= NULL
;
1058 MEMORY_BASIC_INFORMATION BasicInfo
;
1062 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
1063 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
1064 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
1065 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
1066 Length
,ResultLength
);
1068 PreviousMode
= ExGetPreviousMode();
1070 if (PreviousMode
!= KernelMode
)
1074 ProbeForWrite(VirtualMemoryInformation
,
1078 if (UnsafeResultLength
) ProbeForWriteSize_t(UnsafeResultLength
);
1080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1082 /* Return the exception code */
1083 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1088 if (Address
>= MmSystemRangeStart
)
1090 DPRINT1("Invalid parameter\n");
1091 return STATUS_INVALID_PARAMETER
;
1094 /* FIXME: Move this inside MiQueryVirtualMemory */
1095 if (VirtualMemoryInformationClass
== MemorySectionName
)
1097 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1098 PROCESS_QUERY_INFORMATION
,
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
1110 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
1111 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
1113 if (NT_SUCCESS(Status
))
1115 SectionName
= VirtualMemoryInformation
;
1116 if (PreviousMode
!= KernelMode
)
1120 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1121 SectionName
->SectionFileName
.MaximumLength
= Length
;
1122 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1124 if (UnsafeResultLength
!= NULL
)
1126 *UnsafeResultLength
= ModuleFileName
.Length
;
1129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1131 Status
= _SEH2_GetExceptionCode();
1137 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1138 SectionName
->SectionFileName
.MaximumLength
= Length
;
1139 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1141 if (UnsafeResultLength
!= NULL
)
1143 *UnsafeResultLength
= ModuleFileName
.Length
;
1147 ObDereferenceObject(Process
);
1152 Status
= MiQueryVirtualMemory(ProcessHandle
,
1154 VirtualMemoryInformationClass
,
1160 if (NT_SUCCESS(Status
))
1162 if (PreviousMode
!= KernelMode
)
1166 if (ResultLength
> 0)
1168 ProbeForWrite(VirtualMemoryInformation
,
1171 RtlCopyMemory(VirtualMemoryInformation
,
1175 if (UnsafeResultLength
!= NULL
)
1177 *UnsafeResultLength
= ResultLength
;
1180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1182 Status
= _SEH2_GetExceptionCode();
1188 if (ResultLength
> 0)
1190 RtlCopyMemory(VirtualMemoryInformation
,
1195 if (UnsafeResultLength
!= NULL
)
1197 *UnsafeResultLength
= ResultLength
;
1207 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1208 IN PVOID BaseAddress
,
1209 IN SIZE_T NumberOfBytesToLock
,
1210 OUT PSIZE_T NumberOfBytesLocked OPTIONAL
)
1213 if (NumberOfBytesLocked
) *NumberOfBytesLocked
= 0;
1214 return STATUS_SUCCESS
;
1219 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1220 IN PVOID BaseAddress
,
1221 IN SIZE_T NumberOfBytesToUnlock
,
1222 OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
)
1225 if (NumberOfBytesUnlocked
) *NumberOfBytesUnlocked
= 0;
1226 return STATUS_SUCCESS
;
1231 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1232 IN OUT PVOID
*BaseAddress
,
1233 IN OUT PSIZE_T NumberOfBytesToFlush
,
1234 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1237 return STATUS_SUCCESS
;
1245 NtGetWriteWatch(IN HANDLE ProcessHandle
,
1247 IN PVOID BaseAddress
,
1248 IN ULONG RegionSize
,
1249 IN PVOID
*UserAddressArray
,
1250 OUT PULONG EntriesInUserAddressArray
,
1251 OUT PULONG Granularity
)
1253 if (!EntriesInUserAddressArray
|| !Granularity
)
1255 return STATUS_ACCESS_VIOLATION
;
1258 if (!*EntriesInUserAddressArray
|| !RegionSize
)
1260 return STATUS_INVALID_PARAMETER
;
1263 if (!UserAddressArray
)
1265 return STATUS_ACCESS_VIOLATION
;
1268 /* HACK: Set granularity to PAGE_SIZE */
1269 *Granularity
= PAGE_SIZE
;
1272 return STATUS_NOT_IMPLEMENTED
;
1280 NtResetWriteWatch(IN HANDLE ProcessHandle
,
1281 IN PVOID BaseAddress
,
1282 IN ULONG RegionSize
)
1286 return STATUS_INVALID_PARAMETER
;
1290 return STATUS_NOT_IMPLEMENTED
;