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 **********************************************************/
23 _SEH_DEFINE_LOCALS(MiGetExceptionInfo
)
25 volatile BOOLEAN HaveBadAddress
;
26 volatile ULONG_PTR BadAddress
;
29 _SEH_FILTER(MiGetExceptionInfo
)
31 _SEH_ACCESS_LOCALS(MiGetExceptionInfo
);
32 EXCEPTION_POINTERS
*ExceptionInfo
= _SEH_GetExceptionPointers();
33 PEXCEPTION_RECORD ExceptionRecord
;
37 _SEH_VAR(HaveBadAddress
) = FALSE
;
39 /* Get the exception record */
40 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
42 /* Look at the exception code */
43 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
44 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
45 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
47 /* We can tell the address if we have more than one parameter */
48 if (ExceptionRecord
->NumberParameters
> 1)
50 /* Return the address */
51 _SEH_VAR(HaveBadAddress
) = TRUE
;
52 _SEH_VAR(BadAddress
) = ExceptionRecord
->ExceptionInformation
[1];
56 /* Continue executing the next handler */
57 return EXCEPTION_EXECUTE_HANDLER
;
62 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
63 IN PVOID SourceAddress
,
64 IN PEPROCESS TargetProcess
,
65 OUT PVOID TargetAddress
,
67 IN KPROCESSOR_MODE PreviousMode
,
68 OUT PSIZE_T ReturnSize
)
70 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
71 PMDL Mdl
= (PMDL
)MdlBuffer
;
72 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
73 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
75 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
78 _SEH_DECLARE_LOCALS(MiGetExceptionInfo
);
79 NTSTATUS Status
= STATUS_SUCCESS
;
82 /* Calculate the maximum amount of data to move */
83 TotalSize
= (MI_MAPPED_COPY_PAGES
- 2) * PAGE_SIZE
;
84 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
85 CurrentSize
= TotalSize
;
86 RemainingSize
= BufferSize
;
88 /* Loop as long as there is still data */
89 while (RemainingSize
> 0)
91 /* Check if this transfer will finish everything off */
92 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
94 /* Attach to the source address space */
95 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
97 /* Reset state for this pass */
100 FailedInMoving
= FALSE
;
101 ASSERT(FailedInProbe
== FALSE
);
103 /* Protect user-mode copy */
106 /* If this is our first time, probe the buffer */
107 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
109 /* Catch a failure here */
110 FailedInProbe
= TRUE
;
113 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
116 FailedInProbe
= FALSE
;
119 /* Initialize and probe and lock the MDL */
120 MmInitializeMdl (Mdl
, CurrentAddress
, CurrentSize
);
121 MmProbeAndLockPages (Mdl
, PreviousMode
, IoReadAccess
);
124 /* Now map the pages */
125 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
133 /* Use our SEH handler to pick this up */
134 FailedInMapping
= TRUE
;
135 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
138 /* Now let go of the source and grab to the target process */
139 KeUnstackDetachProcess(&ApcState
);
140 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
142 /* Check if this is our first time through */
143 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
145 /* Catch a failure here */
146 FailedInProbe
= TRUE
;
149 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
152 FailedInProbe
= FALSE
;
155 /* Now do the actual move */
156 FailedInMoving
= TRUE
;
157 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
159 _SEH_EXCEPT(MiGetExceptionInfo
)
161 /* Detach from whoever we may be attached to */
162 KeUnstackDetachProcess(&ApcState
);
164 /* Check if we had mapped the pages */
165 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
167 /* Check if we had locked the pages */
168 if (PagesLocked
) MmUnlockPages(Mdl
);
170 /* Check if we failed during the probe or mapping */
171 if ((FailedInProbe
) || (FailedInMapping
))
174 Status
= _SEH_GetExceptionCode();
175 _SEH_YIELD(return Status
);
178 /* Otherwise, we failed probably during the move */
179 *ReturnSize
= BufferSize
- RemainingSize
;
182 /* Check if we know exactly where we stopped copying */
183 if (_SEH_VAR(HaveBadAddress
))
185 /* Return the exact number of bytes copied */
186 *ReturnSize
= _SEH_VAR(BadAddress
) - (ULONG_PTR
)SourceAddress
;
190 /* Return partial copy */
191 Status
= STATUS_PARTIAL_COPY
;
195 /* Check for SEH status */
196 if (Status
!= STATUS_SUCCESS
) return Status
;
198 /* Detach from target */
199 KeUnstackDetachProcess(&ApcState
);
201 /* Unmap and unlock */
202 MmUnmapLockedPages(MdlAddress
, Mdl
);
205 /* Update location and size */
206 RemainingSize
-= CurrentSize
;
207 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
208 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
212 *ReturnSize
= BufferSize
;
213 return STATUS_SUCCESS
;
218 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
219 IN PVOID SourceAddress
,
220 IN PEPROCESS TargetProcess
,
221 OUT PVOID TargetAddress
,
222 IN SIZE_T BufferSize
,
223 IN KPROCESSOR_MODE PreviousMode
,
224 OUT PSIZE_T ReturnSize
)
226 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
227 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
228 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
229 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
232 _SEH_DECLARE_LOCALS(MiGetExceptionInfo
);
233 NTSTATUS Status
= STATUS_SUCCESS
;
236 /* Calculate the maximum amount of data to move */
237 TotalSize
= MI_MAX_TRANSFER_SIZE
;
238 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
239 CurrentSize
= TotalSize
;
240 RemainingSize
= BufferSize
;
242 /* Check if we can use the stack */
243 if (BufferSize
<= MI_POOL_COPY_BYTES
)
246 PoolAddress
= (PVOID
)StackBuffer
;
251 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, TAG_VM
);
252 if (!PoolAddress
) ASSERT(FALSE
);
253 HavePoolAddress
= TRUE
;
256 /* Loop as long as there is still data */
257 while (RemainingSize
> 0)
259 /* Check if this transfer will finish everything off */
260 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
262 /* Attach to the source address space */
263 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
265 /* Reset state for this pass */
266 FailedInMoving
= FALSE
;
267 ASSERT(FailedInProbe
== FALSE
);
269 /* Protect user-mode copy */
272 /* If this is our first time, probe the buffer */
273 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
275 /* Catch a failure here */
276 FailedInProbe
= TRUE
;
279 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
282 FailedInProbe
= FALSE
;
286 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
288 /* Now let go of the source and grab to the target process */
289 KeUnstackDetachProcess(&ApcState
);
290 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
292 /* Check if this is our first time through */
293 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
295 /* Catch a failure here */
296 FailedInProbe
= TRUE
;
299 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
302 FailedInProbe
= FALSE
;
305 /* Now do the actual move */
306 FailedInMoving
= TRUE
;
307 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
309 _SEH_EXCEPT(MiGetExceptionInfo
)
311 /* Detach from whoever we may be attached to */
312 KeUnstackDetachProcess(&ApcState
);
314 /* Check if we had allocated pool */
315 if (HavePoolAddress
) ExFreePool(PoolAddress
);
317 /* Check if we failed during the probe */
321 Status
= _SEH_GetExceptionCode();
322 _SEH_YIELD(return Status
);
325 /* Otherwise, we failed probably during the move */
326 *ReturnSize
= BufferSize
- RemainingSize
;
329 /* Check if we know exactly where we stopped copying */
330 if (_SEH_VAR(HaveBadAddress
))
332 /* Return the exact number of bytes copied */
333 *ReturnSize
= _SEH_VAR(BadAddress
) - (ULONG_PTR
)SourceAddress
;
337 /* Return partial copy */
338 Status
= STATUS_PARTIAL_COPY
;
342 /* Check for SEH status */
343 if (Status
!= STATUS_SUCCESS
) return Status
;
345 /* Detach from target */
346 KeUnstackDetachProcess(&ApcState
);
348 /* Update location and size */
349 RemainingSize
-= CurrentSize
;
350 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
351 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
354 /* Check if we had allocated pool */
355 if (HavePoolAddress
) ExFreePool(PoolAddress
);
358 *ReturnSize
= BufferSize
;
359 return STATUS_SUCCESS
;
364 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
365 IN PVOID SourceAddress
,
366 IN PEPROCESS TargetProcess
,
367 OUT PVOID TargetAddress
,
368 IN SIZE_T BufferSize
,
369 IN KPROCESSOR_MODE PreviousMode
,
370 OUT PSIZE_T ReturnSize
)
373 PEPROCESS Process
= SourceProcess
;
375 /* Don't accept zero-sized buffers */
376 if (!BufferSize
) return STATUS_SUCCESS
;
378 /* If we are copying from ourselves, lock the target instead */
379 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
381 /* Acquire rundown protection */
382 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
385 return STATUS_PROCESS_IS_TERMINATING
;
388 /* See if we should use the pool copy */
389 if (BufferSize
> MI_POOL_COPY_BYTES
)
392 Status
= MiDoMappedCopy(SourceProcess
,
403 Status
= MiDoPoolCopy(SourceProcess
,
412 /* Release the lock */
413 ExReleaseRundownProtection(&Process
->RundownProtect
);
418 MiQueryVirtualMemory(IN HANDLE ProcessHandle
,
420 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
421 OUT PVOID VirtualMemoryInformation
,
423 OUT PSIZE_T ResultLength
)
427 MEMORY_AREA
* MemoryArea
;
428 PMM_AVL_TABLE AddressSpace
;
430 Status
= ObReferenceObjectByHandle(ProcessHandle
,
431 PROCESS_QUERY_INFORMATION
,
437 if (!NT_SUCCESS(Status
))
439 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
443 AddressSpace
= &Process
->VadRoot
;
445 MmLockAddressSpace(AddressSpace
);
446 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
447 switch(VirtualMemoryInformationClass
)
449 case MemoryBasicInformation
:
451 PMEMORY_BASIC_INFORMATION Info
=
452 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
453 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
455 MmUnlockAddressSpace(AddressSpace
);
456 ObDereferenceObject(Process
);
457 return(STATUS_INFO_LENGTH_MISMATCH
);
460 if (MemoryArea
== NULL
)
463 Info
->State
= MEM_FREE
;
464 Info
->Protect
= PAGE_NOACCESS
;
465 Info
->AllocationProtect
= 0;
466 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
467 Info
->AllocationBase
= NULL
;
468 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
469 Status
= STATUS_SUCCESS
;
470 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
474 switch(MemoryArea
->Type
)
476 case MEMORY_AREA_VIRTUAL_MEMORY
:
477 case MEMORY_AREA_PEB_OR_TEB
:
478 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
482 case MEMORY_AREA_SECTION_VIEW
:
483 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
487 case MEMORY_AREA_NO_ACCESS
:
488 Info
->Type
= MEM_PRIVATE
;
489 Info
->State
= MEM_RESERVE
;
490 Info
->Protect
= MemoryArea
->Protect
;
491 Info
->AllocationProtect
= MemoryArea
->Protect
;
492 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
493 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
494 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
495 (ULONG_PTR
)MemoryArea
->StartingAddress
;
496 Status
= STATUS_SUCCESS
;
497 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
500 case MEMORY_AREA_SHARED_DATA
:
501 Info
->Type
= MEM_PRIVATE
;
502 Info
->State
= MEM_COMMIT
;
503 Info
->Protect
= MemoryArea
->Protect
;
504 Info
->AllocationProtect
= MemoryArea
->Protect
;
505 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
506 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
507 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
508 (ULONG_PTR
)MemoryArea
->StartingAddress
;
509 Status
= STATUS_SUCCESS
;
510 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
513 case MEMORY_AREA_SYSTEM
:
515 Info
->State
= MEM_COMMIT
;
516 Info
->Protect
= MemoryArea
->Protect
;
517 Info
->AllocationProtect
= MemoryArea
->Protect
;
518 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
519 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
520 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
521 (ULONG_PTR
)MemoryArea
->StartingAddress
;
522 Status
= STATUS_SUCCESS
;
523 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
526 case MEMORY_AREA_KERNEL_STACK
:
528 Info
->State
= MEM_COMMIT
;
529 Info
->Protect
= MemoryArea
->Protect
;
530 Info
->AllocationProtect
= MemoryArea
->Protect
;
531 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
532 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
533 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
534 (ULONG_PTR
)MemoryArea
->StartingAddress
;
535 Status
= STATUS_SUCCESS
;
536 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
539 case MEMORY_AREA_PAGED_POOL
:
541 Info
->State
= MEM_COMMIT
;
542 Info
->Protect
= MemoryArea
->Protect
;
543 Info
->AllocationProtect
= MemoryArea
->Protect
;
544 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
545 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
546 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
547 (ULONG_PTR
)MemoryArea
->StartingAddress
;
548 Status
= STATUS_SUCCESS
;
549 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
553 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
554 Status
= STATUS_UNSUCCESSFUL
;
563 Status
= STATUS_INVALID_INFO_CLASS
;
569 MmUnlockAddressSpace(AddressSpace
);
570 ObDereferenceObject(Process
);
576 MiProtectVirtualMemory(IN PEPROCESS Process
,
577 IN OUT PVOID
*BaseAddress
,
578 IN OUT PSIZE_T NumberOfBytesToProtect
,
579 IN ULONG NewAccessProtection
,
580 OUT PULONG OldAccessProtection OPTIONAL
)
582 PMEMORY_AREA MemoryArea
;
583 PMM_AVL_TABLE AddressSpace
;
584 ULONG OldAccessProtection_
;
587 *NumberOfBytesToProtect
=
588 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
589 PAGE_ROUND_DOWN(*BaseAddress
);
590 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
592 AddressSpace
= &Process
->VadRoot
;
594 MmLockAddressSpace(AddressSpace
);
595 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
596 if (MemoryArea
== NULL
)
598 MmUnlockAddressSpace(AddressSpace
);
599 return STATUS_UNSUCCESSFUL
;
602 if (OldAccessProtection
== NULL
)
603 OldAccessProtection
= &OldAccessProtection_
;
605 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
607 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
608 *NumberOfBytesToProtect
, NewAccessProtection
,
609 OldAccessProtection
);
611 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
613 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
614 *NumberOfBytesToProtect
,
616 OldAccessProtection
);
620 /* FIXME: Should we return failure or success in this case? */
621 Status
= STATUS_CONFLICTING_ADDRESSES
;
624 MmUnlockAddressSpace(AddressSpace
);
629 /* PUBLIC FUNCTIONS ***********************************************************/
636 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
647 MmSecureVirtualMemory(IN PVOID Address
,
660 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
665 /* SYSTEM CALLS ***************************************************************/
669 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
670 IN PVOID BaseAddress
,
672 IN SIZE_T NumberOfBytesToRead
,
673 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
675 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
677 NTSTATUS Status
= STATUS_SUCCESS
;
678 SIZE_T BytesRead
= 0;
681 /* Check if we came from user mode */
682 if (PreviousMode
!= KernelMode
)
684 /* Validate the read addresses */
685 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
686 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
687 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
688 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
690 /* Don't allow to write into kernel space */
691 return STATUS_ACCESS_VIOLATION
;
694 /* Enter SEH for probe */
697 /* Probe the output value */
698 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
702 /* Get exception code */
703 Status
= _SEH_GetExceptionCode();
707 /* Return if we failed */
708 if (!NT_SUCCESS(Status
)) return Status
;
711 /* Reference the process */
712 Status
= ObReferenceObjectByHandle(ProcessHandle
,
718 if (NT_SUCCESS(Status
))
721 Status
= MmCopyVirtualMemory(Process
,
723 PsGetCurrentProcess(),
729 /* Dereference the process */
730 ObDereferenceObject(Process
);
733 /* Check if the caller sent this parameter */
734 if (NumberOfBytesRead
)
736 /* Enter SEH to guard write */
739 /* Return the number of bytes read */
740 *NumberOfBytesRead
= BytesRead
;
744 /* Handle exception */
745 Status
= _SEH_GetExceptionCode();
756 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
757 IN PVOID BaseAddress
,
759 IN SIZE_T NumberOfBytesToWrite
,
760 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
762 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
764 NTSTATUS Status
= STATUS_SUCCESS
;
765 ULONG BytesWritten
= 0;
768 /* Check if we came from user mode */
769 if (PreviousMode
!= KernelMode
)
771 /* Validate the read addresses */
772 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
773 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
774 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
775 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
777 /* Don't allow to write into kernel space */
778 return STATUS_ACCESS_VIOLATION
;
781 /* Enter SEH for probe */
784 /* Probe the output value */
785 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
789 /* Get exception code */
790 Status
= _SEH_GetExceptionCode();
794 /* Return if we failed */
795 if (!NT_SUCCESS(Status
)) return Status
;
798 /* Reference the process */
799 Status
= ObReferenceObjectByHandle(ProcessHandle
,
805 if (NT_SUCCESS(Status
))
808 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
812 NumberOfBytesToWrite
,
816 /* Dereference the process */
817 ObDereferenceObject(Process
);
820 /* Check if the caller sent this parameter */
821 if (NumberOfBytesWritten
)
823 /* Enter SEH to guard write */
826 /* Return the number of bytes read */
827 *NumberOfBytesWritten
= BytesWritten
;
831 /* Handle exception */
832 Status
= _SEH_GetExceptionCode();
843 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
844 IN OUT PVOID
*UnsafeBaseAddress
,
845 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
846 IN ULONG NewAccessProtection
,
847 OUT PULONG UnsafeOldAccessProtection
)
850 ULONG OldAccessProtection
;
851 PVOID BaseAddress
= NULL
;
852 SIZE_T NumberOfBytesToProtect
= 0;
853 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
854 NTSTATUS Status
= STATUS_SUCCESS
;
856 /* Check if we came from user mode */
857 if (PreviousMode
!= KernelMode
)
859 /* Enter SEH for probing */
862 /* Validate all outputs */
863 ProbeForWritePointer(UnsafeBaseAddress
);
864 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
865 ProbeForWriteUlong(UnsafeOldAccessProtection
);
868 BaseAddress
= *UnsafeBaseAddress
;
869 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
873 /* Get exception code */
874 Status
= _SEH_GetExceptionCode();
878 /* Return on exception */
879 if (!NT_SUCCESS(Status
)) return Status
;
883 /* Capture directly */
884 BaseAddress
= *UnsafeBaseAddress
;
885 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
888 /* Catch illegal base address */
889 if (BaseAddress
> (PVOID
)MmUserProbeAddress
) return STATUS_INVALID_PARAMETER_2
;
891 /* Catch illegal region size */
892 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
895 return STATUS_INVALID_PARAMETER_3
;
898 /* 0 is also illegal */
899 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
901 /* Get a reference to the process */
902 Status
= ObReferenceObjectByHandle(ProcessHandle
,
903 PROCESS_VM_OPERATION
,
908 if (!NT_SUCCESS(Status
)) return Status
;
910 /* Do the actual work */
911 Status
= MiProtectVirtualMemory(Process
,
913 &NumberOfBytesToProtect
,
915 &OldAccessProtection
);
917 /* Release reference */
918 ObDereferenceObject(Process
);
920 /* Enter SEH to return data */
923 /* Return data to user */
924 *UnsafeOldAccessProtection
= OldAccessProtection
;
925 *UnsafeBaseAddress
= BaseAddress
;
926 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
930 /* Catch exception */
931 Status
= _SEH_GetExceptionCode();
940 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
942 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
943 OUT PVOID VirtualMemoryInformation
,
945 OUT PSIZE_T UnsafeResultLength
)
947 NTSTATUS Status
= STATUS_SUCCESS
;
948 SIZE_T ResultLength
= 0;
949 KPROCESSOR_MODE PreviousMode
;
950 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
951 UNICODE_STRING ModuleFileName
;
952 PMEMORY_SECTION_NAME SectionName
= NULL
;
955 MEMORY_BASIC_INFORMATION BasicInfo
;
959 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
960 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
961 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
962 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
963 Length
,ResultLength
);
965 PreviousMode
= ExGetPreviousMode();
967 if (PreviousMode
!= KernelMode
&& UnsafeResultLength
!= NULL
)
971 ProbeForWriteSize_t(UnsafeResultLength
);
975 Status
= _SEH_GetExceptionCode();
979 if (!NT_SUCCESS(Status
))
985 if (Address
>= MmSystemRangeStart
)
987 DPRINT1("Invalid parameter\n");
988 return STATUS_INVALID_PARAMETER
;
991 /* FIXME: Move this inside MiQueryVirtualMemory */
992 if (VirtualMemoryInformationClass
== MemorySectionName
)
994 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
995 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
997 if (NT_SUCCESS(Status
))
999 SectionName
= VirtualMemoryInformation
;
1000 if (PreviousMode
!= KernelMode
)
1004 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1005 SectionName
->SectionFileName
.MaximumLength
= Length
;
1006 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1008 if (UnsafeResultLength
!= NULL
)
1010 *UnsafeResultLength
= ModuleFileName
.Length
;
1015 Status
= _SEH_GetExceptionCode();
1021 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1022 SectionName
->SectionFileName
.MaximumLength
= Length
;
1023 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1025 if (UnsafeResultLength
!= NULL
)
1027 *UnsafeResultLength
= ModuleFileName
.Length
;
1035 Status
= MiQueryVirtualMemory(ProcessHandle
,
1037 VirtualMemoryInformationClass
,
1043 if (NT_SUCCESS(Status
))
1045 if (PreviousMode
!= KernelMode
)
1049 if (ResultLength
> 0)
1051 ProbeForWrite(VirtualMemoryInformation
,
1054 RtlCopyMemory(VirtualMemoryInformation
,
1058 if (UnsafeResultLength
!= NULL
)
1060 *UnsafeResultLength
= ResultLength
;
1065 Status
= _SEH_GetExceptionCode();
1071 if (ResultLength
> 0)
1073 RtlCopyMemory(VirtualMemoryInformation
,
1078 if (UnsafeResultLength
!= NULL
)
1080 *UnsafeResultLength
= ResultLength
;
1090 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1091 IN PVOID BaseAddress
,
1092 IN SIZE_T NumberOfBytesToLock
,
1093 OUT PSIZE_T NumberOfBytesLocked OPTIONAL
)
1096 if (NumberOfBytesLocked
) *NumberOfBytesLocked
= 0;
1097 return STATUS_SUCCESS
;
1102 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1103 IN PVOID BaseAddress
,
1104 IN SIZE_T NumberOfBytesToUnlock
,
1105 OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
)
1108 if (NumberOfBytesUnlocked
) *NumberOfBytesUnlocked
= 0;
1109 return STATUS_SUCCESS
;
1114 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1115 IN OUT PVOID
*BaseAddress
,
1116 IN OUT PSIZE_T NumberOfBytesToFlush
,
1117 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1120 return STATUS_SUCCESS
;