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
19 #define TAG_VM TAG('V', 'm', 'R', 'w')
21 /* PRIVATE FUNCTIONS **********************************************************/
25 MiGetExceptionInfo(EXCEPTION_POINTERS
*ExceptionInfo
, BOOLEAN
* HaveBadAddress
, ULONG_PTR
* BadAddress
)
27 PEXCEPTION_RECORD ExceptionRecord
;
31 *HaveBadAddress
= FALSE
;
33 /* Get the exception record */
34 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
36 /* Look at the exception code */
37 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
38 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
39 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
41 /* We can tell the address if we have more than one parameter */
42 if (ExceptionRecord
->NumberParameters
> 1)
44 /* Return the address */
45 *HaveBadAddress
= TRUE
;
46 *BadAddress
= ExceptionRecord
->ExceptionInformation
[1];
50 /* Continue executing the next handler */
51 return EXCEPTION_EXECUTE_HANDLER
;
56 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
57 IN PVOID SourceAddress
,
58 IN PEPROCESS TargetProcess
,
59 OUT PVOID TargetAddress
,
61 IN KPROCESSOR_MODE PreviousMode
,
62 OUT PSIZE_T ReturnSize
)
64 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
65 PMDL Mdl
= (PMDL
)MdlBuffer
;
66 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
67 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
68 volatile BOOLEAN PagesLocked
;
69 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
70 volatile PVOID MdlAddress
;
72 BOOLEAN HaveBadAddress
;
74 NTSTATUS Status
= STATUS_SUCCESS
;
77 /* Calculate the maximum amount of data to move */
78 TotalSize
= (MI_MAPPED_COPY_PAGES
- 2) * PAGE_SIZE
;
79 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
80 CurrentSize
= TotalSize
;
81 RemainingSize
= BufferSize
;
83 /* Loop as long as there is still data */
84 while (RemainingSize
> 0)
86 /* Check if this transfer will finish everything off */
87 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
89 /* Attach to the source address space */
90 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
92 /* Reset state for this pass */
95 FailedInMoving
= FALSE
;
96 ASSERT(FailedInProbe
== FALSE
);
98 /* Protect user-mode copy */
101 /* If this is our first time, probe the buffer */
102 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
104 /* Catch a failure here */
105 FailedInProbe
= TRUE
;
108 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
111 FailedInProbe
= FALSE
;
114 /* Initialize and probe and lock the MDL */
115 MmInitializeMdl (Mdl
, CurrentAddress
, CurrentSize
);
116 MmProbeAndLockPages (Mdl
, PreviousMode
, IoReadAccess
);
119 /* Now map the pages */
120 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
128 /* Use our SEH handler to pick this up */
129 FailedInMapping
= TRUE
;
130 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
133 /* Now let go of the source and grab to the target process */
134 KeUnstackDetachProcess(&ApcState
);
135 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
137 /* Check if this is our first time through */
138 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
140 /* Catch a failure here */
141 FailedInProbe
= TRUE
;
144 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
147 FailedInProbe
= FALSE
;
150 /* Now do the actual move */
151 FailedInMoving
= TRUE
;
152 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
154 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
156 /* Detach from whoever we may be attached to */
157 KeUnstackDetachProcess(&ApcState
);
159 /* Check if we had mapped the pages */
160 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
162 /* Check if we had locked the pages */
163 if (PagesLocked
) MmUnlockPages(Mdl
);
165 /* Check if we failed during the probe or mapping */
166 if ((FailedInProbe
) || (FailedInMapping
))
169 Status
= _SEH2_GetExceptionCode();
170 _SEH2_YIELD(return Status
);
173 /* Otherwise, we failed probably during the move */
174 *ReturnSize
= BufferSize
- RemainingSize
;
177 /* Check if we know exactly where we stopped copying */
180 /* Return the exact number of bytes copied */
181 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
185 /* Return partial copy */
186 Status
= STATUS_PARTIAL_COPY
;
190 /* Check for SEH status */
191 if (Status
!= STATUS_SUCCESS
) return Status
;
193 /* Detach from target */
194 KeUnstackDetachProcess(&ApcState
);
196 /* Unmap and unlock */
197 MmUnmapLockedPages(MdlAddress
, Mdl
);
200 /* Update location and size */
201 RemainingSize
-= CurrentSize
;
202 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
203 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
207 *ReturnSize
= BufferSize
;
208 return STATUS_SUCCESS
;
213 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
214 IN PVOID SourceAddress
,
215 IN PEPROCESS TargetProcess
,
216 OUT PVOID TargetAddress
,
217 IN SIZE_T BufferSize
,
218 IN KPROCESSOR_MODE PreviousMode
,
219 OUT PSIZE_T ReturnSize
)
221 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
222 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
223 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
224 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
227 BOOLEAN HaveBadAddress
;
228 ULONG_PTR BadAddress
;
229 NTSTATUS Status
= STATUS_SUCCESS
;
232 /* Calculate the maximum amount of data to move */
233 TotalSize
= MI_MAX_TRANSFER_SIZE
;
234 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
235 CurrentSize
= TotalSize
;
236 RemainingSize
= BufferSize
;
238 /* Check if we can use the stack */
239 if (BufferSize
<= MI_POOL_COPY_BYTES
)
242 PoolAddress
= (PVOID
)StackBuffer
;
247 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, TAG_VM
);
248 if (!PoolAddress
) ASSERT(FALSE
);
249 HavePoolAddress
= TRUE
;
252 /* Loop as long as there is still data */
253 while (RemainingSize
> 0)
255 /* Check if this transfer will finish everything off */
256 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
258 /* Attach to the source address space */
259 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
261 /* Reset state for this pass */
262 FailedInMoving
= FALSE
;
263 ASSERT(FailedInProbe
== FALSE
);
265 /* Protect user-mode copy */
268 /* If this is our first time, probe the buffer */
269 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
271 /* Catch a failure here */
272 FailedInProbe
= TRUE
;
275 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
278 FailedInProbe
= FALSE
;
282 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
284 /* Now let go of the source and grab to the target process */
285 KeUnstackDetachProcess(&ApcState
);
286 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
288 /* Check if this is our first time through */
289 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
291 /* Catch a failure here */
292 FailedInProbe
= TRUE
;
295 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
298 FailedInProbe
= FALSE
;
301 /* Now do the actual move */
302 FailedInMoving
= TRUE
;
303 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
305 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
307 /* Detach from whoever we may be attached to */
308 KeUnstackDetachProcess(&ApcState
);
310 /* Check if we had allocated pool */
311 if (HavePoolAddress
) ExFreePool(PoolAddress
);
313 /* Check if we failed during the probe */
317 Status
= _SEH2_GetExceptionCode();
318 _SEH2_YIELD(return Status
);
321 /* Otherwise, we failed probably during the move */
322 *ReturnSize
= BufferSize
- RemainingSize
;
325 /* Check if we know exactly where we stopped copying */
328 /* Return the exact number of bytes copied */
329 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
333 /* Return partial copy */
334 Status
= STATUS_PARTIAL_COPY
;
338 /* Check for SEH status */
339 if (Status
!= STATUS_SUCCESS
) return Status
;
341 /* Detach from target */
342 KeUnstackDetachProcess(&ApcState
);
344 /* Update location and size */
345 RemainingSize
-= CurrentSize
;
346 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
347 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
350 /* Check if we had allocated pool */
351 if (HavePoolAddress
) ExFreePool(PoolAddress
);
354 *ReturnSize
= BufferSize
;
355 return STATUS_SUCCESS
;
360 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
361 IN PVOID SourceAddress
,
362 IN PEPROCESS TargetProcess
,
363 OUT PVOID TargetAddress
,
364 IN SIZE_T BufferSize
,
365 IN KPROCESSOR_MODE PreviousMode
,
366 OUT PSIZE_T ReturnSize
)
369 PEPROCESS Process
= SourceProcess
;
371 /* Don't accept zero-sized buffers */
372 if (!BufferSize
) return STATUS_SUCCESS
;
374 /* If we are copying from ourselves, lock the target instead */
375 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
377 /* Acquire rundown protection */
378 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
381 return STATUS_PROCESS_IS_TERMINATING
;
384 /* See if we should use the pool copy */
385 if (BufferSize
> MI_POOL_COPY_BYTES
)
388 Status
= MiDoMappedCopy(SourceProcess
,
399 Status
= MiDoPoolCopy(SourceProcess
,
408 /* Release the lock */
409 ExReleaseRundownProtection(&Process
->RundownProtect
);
414 MiQueryVirtualMemory(IN HANDLE ProcessHandle
,
416 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
417 OUT PVOID VirtualMemoryInformation
,
419 OUT PSIZE_T ResultLength
)
423 MEMORY_AREA
* MemoryArea
;
424 PMMSUPPORT AddressSpace
;
426 Status
= ObReferenceObjectByHandle(ProcessHandle
,
427 PROCESS_QUERY_INFORMATION
,
433 if (!NT_SUCCESS(Status
))
435 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
439 AddressSpace
= &Process
->Vm
;
441 MmLockAddressSpace(AddressSpace
);
442 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
443 switch(VirtualMemoryInformationClass
)
445 case MemoryBasicInformation
:
447 PMEMORY_BASIC_INFORMATION Info
=
448 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
449 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
451 MmUnlockAddressSpace(AddressSpace
);
452 ObDereferenceObject(Process
);
453 return(STATUS_INFO_LENGTH_MISMATCH
);
456 if (MemoryArea
== NULL
)
459 Info
->State
= MEM_FREE
;
460 Info
->Protect
= PAGE_NOACCESS
;
461 Info
->AllocationProtect
= 0;
462 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
463 Info
->AllocationBase
= NULL
;
464 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
465 Status
= STATUS_SUCCESS
;
466 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
470 switch(MemoryArea
->Type
)
472 case MEMORY_AREA_VIRTUAL_MEMORY
:
473 case MEMORY_AREA_PEB_OR_TEB
:
474 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
478 case MEMORY_AREA_SECTION_VIEW
:
479 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
483 case MEMORY_AREA_NO_ACCESS
:
484 Info
->Type
= MEM_PRIVATE
;
485 Info
->State
= MEM_RESERVE
;
486 Info
->Protect
= MemoryArea
->Protect
;
487 Info
->AllocationProtect
= MemoryArea
->Protect
;
488 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
489 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
490 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
491 (ULONG_PTR
)MemoryArea
->StartingAddress
;
492 Status
= STATUS_SUCCESS
;
493 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
496 case MEMORY_AREA_SHARED_DATA
:
497 Info
->Type
= MEM_PRIVATE
;
498 Info
->State
= MEM_COMMIT
;
499 Info
->Protect
= MemoryArea
->Protect
;
500 Info
->AllocationProtect
= MemoryArea
->Protect
;
501 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
502 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
503 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
504 (ULONG_PTR
)MemoryArea
->StartingAddress
;
505 Status
= STATUS_SUCCESS
;
506 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
509 case MEMORY_AREA_SYSTEM
:
511 Info
->State
= MEM_COMMIT
;
512 Info
->Protect
= MemoryArea
->Protect
;
513 Info
->AllocationProtect
= MemoryArea
->Protect
;
514 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
515 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
516 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
517 (ULONG_PTR
)MemoryArea
->StartingAddress
;
518 Status
= STATUS_SUCCESS
;
519 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
522 case MEMORY_AREA_KERNEL_STACK
:
524 Info
->State
= MEM_COMMIT
;
525 Info
->Protect
= MemoryArea
->Protect
;
526 Info
->AllocationProtect
= MemoryArea
->Protect
;
527 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
528 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
529 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
530 (ULONG_PTR
)MemoryArea
->StartingAddress
;
531 Status
= STATUS_SUCCESS
;
532 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
535 case MEMORY_AREA_PAGED_POOL
:
537 Info
->State
= MEM_COMMIT
;
538 Info
->Protect
= MemoryArea
->Protect
;
539 Info
->AllocationProtect
= MemoryArea
->Protect
;
540 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
541 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
542 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
543 (ULONG_PTR
)MemoryArea
->StartingAddress
;
544 Status
= STATUS_SUCCESS
;
545 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
549 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
550 Status
= STATUS_UNSUCCESSFUL
;
559 Status
= STATUS_INVALID_INFO_CLASS
;
565 MmUnlockAddressSpace(AddressSpace
);
566 ObDereferenceObject(Process
);
572 MiProtectVirtualMemory(IN PEPROCESS Process
,
573 IN OUT PVOID
*BaseAddress
,
574 IN OUT PSIZE_T NumberOfBytesToProtect
,
575 IN ULONG NewAccessProtection
,
576 OUT PULONG OldAccessProtection OPTIONAL
)
578 PMEMORY_AREA MemoryArea
;
579 PMMSUPPORT AddressSpace
;
580 ULONG OldAccessProtection_
;
583 *NumberOfBytesToProtect
=
584 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
585 PAGE_ROUND_DOWN(*BaseAddress
);
586 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
588 AddressSpace
= &Process
->Vm
;
590 MmLockAddressSpace(AddressSpace
);
591 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
592 if (MemoryArea
== NULL
)
594 MmUnlockAddressSpace(AddressSpace
);
595 return STATUS_UNSUCCESSFUL
;
598 if (OldAccessProtection
== NULL
)
599 OldAccessProtection
= &OldAccessProtection_
;
601 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
603 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
604 *NumberOfBytesToProtect
, NewAccessProtection
,
605 OldAccessProtection
);
607 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
609 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
610 *NumberOfBytesToProtect
,
612 OldAccessProtection
);
616 /* FIXME: Should we return failure or success in this case? */
617 Status
= STATUS_CONFLICTING_ADDRESSES
;
620 MmUnlockAddressSpace(AddressSpace
);
625 /* PUBLIC FUNCTIONS ***********************************************************/
632 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
643 MmSecureVirtualMemory(IN PVOID Address
,
656 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
661 /* SYSTEM CALLS ***************************************************************/
665 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
666 IN PVOID BaseAddress
,
668 IN SIZE_T NumberOfBytesToRead
,
669 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
671 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
673 NTSTATUS Status
= STATUS_SUCCESS
;
674 SIZE_T BytesRead
= 0;
677 /* Check if we came from user mode */
678 if (PreviousMode
!= KernelMode
)
680 /* Validate the read addresses */
681 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
682 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
683 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
684 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
686 /* Don't allow to write into kernel space */
687 return STATUS_ACCESS_VIOLATION
;
690 /* Enter SEH for probe */
693 /* Probe the output value */
694 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
698 /* Get exception code */
699 Status
= _SEH2_GetExceptionCode();
703 /* Return if we failed */
704 if (!NT_SUCCESS(Status
)) return Status
;
707 /* Reference the process */
708 Status
= ObReferenceObjectByHandle(ProcessHandle
,
714 if (NT_SUCCESS(Status
))
717 Status
= MmCopyVirtualMemory(Process
,
719 PsGetCurrentProcess(),
725 /* Dereference the process */
726 ObDereferenceObject(Process
);
729 /* Check if the caller sent this parameter */
730 if (NumberOfBytesRead
)
732 /* Enter SEH to guard write */
735 /* Return the number of bytes read */
736 *NumberOfBytesRead
= BytesRead
;
738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
740 /* Handle exception */
741 Status
= _SEH2_GetExceptionCode();
752 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
753 IN PVOID BaseAddress
,
755 IN SIZE_T NumberOfBytesToWrite
,
756 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
758 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
760 NTSTATUS Status
= STATUS_SUCCESS
;
761 ULONG BytesWritten
= 0;
764 /* Check if we came from user mode */
765 if (PreviousMode
!= KernelMode
)
767 /* Validate the read addresses */
768 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
769 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
770 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
771 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
773 /* Don't allow to write into kernel space */
774 return STATUS_ACCESS_VIOLATION
;
777 /* Enter SEH for probe */
780 /* Probe the output value */
781 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
785 /* Get exception code */
786 Status
= _SEH2_GetExceptionCode();
790 /* Return if we failed */
791 if (!NT_SUCCESS(Status
)) return Status
;
794 /* Reference the process */
795 Status
= ObReferenceObjectByHandle(ProcessHandle
,
801 if (NT_SUCCESS(Status
))
804 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
808 NumberOfBytesToWrite
,
812 /* Dereference the process */
813 ObDereferenceObject(Process
);
816 /* Check if the caller sent this parameter */
817 if (NumberOfBytesWritten
)
819 /* Enter SEH to guard write */
822 /* Return the number of bytes read */
823 *NumberOfBytesWritten
= BytesWritten
;
825 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
827 /* Handle exception */
828 Status
= _SEH2_GetExceptionCode();
839 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
840 IN OUT PVOID
*UnsafeBaseAddress
,
841 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
842 IN ULONG NewAccessProtection
,
843 OUT PULONG UnsafeOldAccessProtection
)
846 ULONG OldAccessProtection
;
848 PVOID BaseAddress
= NULL
;
849 SIZE_T NumberOfBytesToProtect
= 0;
850 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
851 NTSTATUS Status
= STATUS_SUCCESS
;
854 /* Check for valid protection flags */
855 Protection
= NewAccessProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
856 if (Protection
!= PAGE_NOACCESS
&&
857 Protection
!= PAGE_READONLY
&&
858 Protection
!= PAGE_READWRITE
&&
859 Protection
!= PAGE_WRITECOPY
&&
860 Protection
!= PAGE_EXECUTE
&&
861 Protection
!= PAGE_EXECUTE_READ
&&
862 Protection
!= PAGE_EXECUTE_READWRITE
&&
863 Protection
!= PAGE_EXECUTE_WRITECOPY
)
865 return STATUS_INVALID_PAGE_PROTECTION
;
868 /* Check if we came from user mode */
869 if (PreviousMode
!= KernelMode
)
871 /* Enter SEH for probing */
874 /* Validate all outputs */
875 ProbeForWritePointer(UnsafeBaseAddress
);
876 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
877 ProbeForWriteUlong(UnsafeOldAccessProtection
);
880 BaseAddress
= *UnsafeBaseAddress
;
881 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
885 /* Get exception code */
886 Status
= _SEH2_GetExceptionCode();
890 /* Return on exception */
891 if (!NT_SUCCESS(Status
)) return Status
;
895 /* Capture directly */
896 BaseAddress
= *UnsafeBaseAddress
;
897 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
900 /* Catch illegal base address */
901 if (BaseAddress
> (PVOID
)MmUserProbeAddress
) return STATUS_INVALID_PARAMETER_2
;
903 /* Catch illegal region size */
904 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
907 return STATUS_INVALID_PARAMETER_3
;
910 /* 0 is also illegal */
911 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
913 /* Get a reference to the process */
914 Status
= ObReferenceObjectByHandle(ProcessHandle
,
915 PROCESS_VM_OPERATION
,
920 if (!NT_SUCCESS(Status
)) return Status
;
922 /* Do the actual work */
923 Status
= MiProtectVirtualMemory(Process
,
925 &NumberOfBytesToProtect
,
927 &OldAccessProtection
);
929 /* Release reference */
930 ObDereferenceObject(Process
);
932 /* Enter SEH to return data */
935 /* Return data to user */
936 *UnsafeOldAccessProtection
= OldAccessProtection
;
937 *UnsafeBaseAddress
= BaseAddress
;
938 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
940 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
942 /* Catch exception */
943 Status
= _SEH2_GetExceptionCode();
952 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
954 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
955 OUT PVOID VirtualMemoryInformation
,
957 OUT PSIZE_T UnsafeResultLength
)
959 NTSTATUS Status
= STATUS_SUCCESS
;
960 SIZE_T ResultLength
= 0;
961 KPROCESSOR_MODE PreviousMode
;
962 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
963 UNICODE_STRING ModuleFileName
;
964 PMEMORY_SECTION_NAME SectionName
= NULL
;
968 MEMORY_BASIC_INFORMATION BasicInfo
;
972 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
973 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
974 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
975 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
976 Length
,ResultLength
);
978 PreviousMode
= ExGetPreviousMode();
980 if (PreviousMode
!= KernelMode
)
984 ProbeForWrite(VirtualMemoryInformation
,
988 if (UnsafeResultLength
) ProbeForWriteSize_t(UnsafeResultLength
);
990 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
992 Status
= _SEH2_GetExceptionCode();
996 if (!NT_SUCCESS(Status
))
1002 if (Address
>= MmSystemRangeStart
)
1004 DPRINT1("Invalid parameter\n");
1005 return STATUS_INVALID_PARAMETER
;
1008 /* FIXME: Move this inside MiQueryVirtualMemory */
1009 if (VirtualMemoryInformationClass
== MemorySectionName
)
1011 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1012 PROCESS_QUERY_INFORMATION
,
1018 if (!NT_SUCCESS(Status
))
1020 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
1024 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
1025 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
1027 if (NT_SUCCESS(Status
))
1029 SectionName
= VirtualMemoryInformation
;
1030 if (PreviousMode
!= KernelMode
)
1034 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1035 SectionName
->SectionFileName
.MaximumLength
= Length
;
1036 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1038 if (UnsafeResultLength
!= NULL
)
1040 *UnsafeResultLength
= ModuleFileName
.Length
;
1043 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1045 Status
= _SEH2_GetExceptionCode();
1051 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1052 SectionName
->SectionFileName
.MaximumLength
= Length
;
1053 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1055 if (UnsafeResultLength
!= NULL
)
1057 *UnsafeResultLength
= ModuleFileName
.Length
;
1061 ObDereferenceObject(Process
);
1066 Status
= MiQueryVirtualMemory(ProcessHandle
,
1068 VirtualMemoryInformationClass
,
1074 if (NT_SUCCESS(Status
))
1076 if (PreviousMode
!= KernelMode
)
1080 if (ResultLength
> 0)
1082 ProbeForWrite(VirtualMemoryInformation
,
1085 RtlCopyMemory(VirtualMemoryInformation
,
1089 if (UnsafeResultLength
!= NULL
)
1091 *UnsafeResultLength
= ResultLength
;
1094 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1096 Status
= _SEH2_GetExceptionCode();
1102 if (ResultLength
> 0)
1104 RtlCopyMemory(VirtualMemoryInformation
,
1109 if (UnsafeResultLength
!= NULL
)
1111 *UnsafeResultLength
= ResultLength
;
1121 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1122 IN PVOID BaseAddress
,
1123 IN SIZE_T NumberOfBytesToLock
,
1124 OUT PSIZE_T NumberOfBytesLocked OPTIONAL
)
1127 if (NumberOfBytesLocked
) *NumberOfBytesLocked
= 0;
1128 return STATUS_SUCCESS
;
1133 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1134 IN PVOID BaseAddress
,
1135 IN SIZE_T NumberOfBytesToUnlock
,
1136 OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
)
1139 if (NumberOfBytesUnlocked
) *NumberOfBytesUnlocked
= 0;
1140 return STATUS_SUCCESS
;
1145 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1146 IN OUT PVOID
*BaseAddress
,
1147 IN OUT PSIZE_T NumberOfBytesToFlush
,
1148 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1151 return STATUS_SUCCESS
;