- Removed the process from the parameter list of MmCreateMemoryArea.
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/virtual.c
6 * PURPOSE: Implementing operations on virtual memory.
7 *
8 * PROGRAMMERS: David Welch
9 */
10
11 /* INCLUDE *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* FUNCTIONS *****************************************************************/
19
20 NTSTATUS STDCALL
21 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
22 IN PVOID BaseAddress,
23 IN ULONG NumberOfBytesToFlush,
24 OUT PULONG NumberOfBytesFlushed OPTIONAL)
25 /*
26 * FUNCTION: Flushes virtual memory to file
27 * ARGUMENTS:
28 * ProcessHandle = Points to the process that allocated the virtual
29 * memory
30 * BaseAddress = Points to the memory address
31 * NumberOfBytesToFlush = Limits the range to flush,
32 * NumberOfBytesFlushed = Actual number of bytes flushed
33 * RETURNS: Status
34 */
35 {
36 /* This should be implemented once we support network filesystems */
37 DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
38 return(STATUS_SUCCESS);
39 }
40
41
42 NTSTATUS STDCALL
43 MiLockVirtualMemory(HANDLE ProcessHandle,
44 PVOID BaseAddress,
45 ULONG NumberOfBytesToLock,
46 PULONG NumberOfBytesLocked,
47 PObReferenceObjectByHandle pObReferenceObjectByHandle,
48 PMmCreateMdl pMmCreateMdl,
49 PObDereferenceObject pObDereferenceObject,
50 PMmProbeAndLockPages pMmProbeAndLockPages,
51 PExFreePool pExFreePool)
52 {
53 PEPROCESS Process;
54 NTSTATUS Status;
55 PMDL Mdl;
56
57 Status = pObReferenceObjectByHandle(ProcessHandle,
58 PROCESS_VM_WRITE,
59 NULL,
60 UserMode,
61 (PVOID*)(&Process),
62 NULL);
63 if (!NT_SUCCESS(Status))
64 return(Status);
65
66 Mdl = pMmCreateMdl(NULL,
67 BaseAddress,
68 NumberOfBytesToLock);
69 if (Mdl == NULL)
70 {
71 pObDereferenceObject(Process);
72 return(STATUS_NO_MEMORY);
73 }
74
75 pMmProbeAndLockPages(Mdl,
76 UserMode,
77 IoWriteAccess);
78
79 pExFreePool(Mdl);
80
81 pObDereferenceObject(Process);
82
83 *NumberOfBytesLocked = NumberOfBytesToLock;
84 return(STATUS_SUCCESS);
85 }
86
87
88 NTSTATUS STDCALL
89 NtLockVirtualMemory(HANDLE ProcessHandle,
90 PVOID BaseAddress,
91 ULONG NumberOfBytesToLock,
92 PULONG NumberOfBytesLocked)
93 {
94 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
95 "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
96 ProcessHandle,
97 BaseAddress,
98 NumberOfBytesToLock,
99 NumberOfBytesLocked);
100
101 return MiLockVirtualMemory(ProcessHandle,
102 BaseAddress,
103 NumberOfBytesToLock,
104 NumberOfBytesLocked,
105 ObReferenceObjectByHandle,
106 MmCreateMdl,
107 ObfDereferenceObject,
108 MmProbeAndLockPages,
109 ExFreePool);
110 }
111
112
113 NTSTATUS FASTCALL
114 MiQueryVirtualMemory (IN HANDLE ProcessHandle,
115 IN PVOID Address,
116 IN CINT VirtualMemoryInformationClass,
117 OUT PVOID VirtualMemoryInformation,
118 IN ULONG Length,
119 OUT PULONG ResultLength)
120 {
121 NTSTATUS Status;
122 PEPROCESS Process;
123 MEMORY_AREA* MemoryArea;
124 PMADDRESS_SPACE AddressSpace;
125
126 if (Address < MmSystemRangeStart)
127 {
128 Status = ObReferenceObjectByHandle(ProcessHandle,
129 PROCESS_QUERY_INFORMATION,
130 NULL,
131 UserMode,
132 (PVOID*)(&Process),
133 NULL);
134
135 if (!NT_SUCCESS(Status))
136 {
137 DPRINT("NtQueryVirtualMemory() = %x\n",Status);
138 return(Status);
139 }
140 AddressSpace = &Process->AddressSpace;
141 }
142 else
143 {
144 AddressSpace = MmGetKernelAddressSpace();
145 }
146 MmLockAddressSpace(AddressSpace);
147 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
148 switch(VirtualMemoryInformationClass)
149 {
150 case MemoryBasicInformation:
151 {
152 PMEMORY_BASIC_INFORMATION Info =
153 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
154 if (Length != sizeof(MEMORY_BASIC_INFORMATION))
155 {
156 MmUnlockAddressSpace(AddressSpace);
157 ObDereferenceObject(Process);
158 return(STATUS_INFO_LENGTH_MISMATCH);
159 }
160
161 if (MemoryArea == NULL)
162 {
163 Info->Type = 0;
164 Info->State = MEM_FREE;
165 Info->Protect = PAGE_NOACCESS;
166 Info->AllocationProtect = 0;
167 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
168 Info->AllocationBase = NULL;
169 Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
170 Status = STATUS_SUCCESS;
171 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
172 }
173 else
174 {
175 switch(MemoryArea->Type)
176 {
177 case MEMORY_AREA_VIRTUAL_MEMORY:
178 case MEMORY_AREA_PEB_OR_TEB:
179 Status = MmQueryAnonMem(MemoryArea, Address, Info,
180 ResultLength);
181 break;
182 case MEMORY_AREA_SECTION_VIEW:
183 Status = MmQuerySectionView(MemoryArea, Address, Info,
184 ResultLength);
185 break;
186 case MEMORY_AREA_NO_ACCESS:
187 Info->Type = MEM_PRIVATE;
188 Info->State = MEM_RESERVE;
189 Info->Protect = MemoryArea->Protect;
190 Info->AllocationProtect = MemoryArea->Protect;
191 Info->BaseAddress = MemoryArea->StartingAddress;
192 Info->AllocationBase = MemoryArea->StartingAddress;
193 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
194 (ULONG_PTR)MemoryArea->StartingAddress;
195 Status = STATUS_SUCCESS;
196 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
197 break;
198 case MEMORY_AREA_SHARED_DATA:
199 Info->Type = MEM_PRIVATE;
200 Info->State = MEM_COMMIT;
201 Info->Protect = MemoryArea->Protect;
202 Info->AllocationProtect = MemoryArea->Protect;
203 Info->BaseAddress = MemoryArea->StartingAddress;
204 Info->AllocationBase = MemoryArea->StartingAddress;
205 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
206 (ULONG_PTR)MemoryArea->StartingAddress;
207 Status = STATUS_SUCCESS;
208 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
209 break;
210 case MEMORY_AREA_SYSTEM:
211 Info->Type = 0;
212 Info->State = MEM_COMMIT;
213 Info->Protect = MemoryArea->Protect;
214 Info->AllocationProtect = MemoryArea->Protect;
215 Info->BaseAddress = MemoryArea->StartingAddress;
216 Info->AllocationBase = MemoryArea->StartingAddress;
217 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
218 (ULONG_PTR)MemoryArea->StartingAddress;
219 Status = STATUS_SUCCESS;
220 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
221 break;
222 case MEMORY_AREA_KERNEL_STACK:
223 Info->Type = 0;
224 Info->State = MEM_COMMIT;
225 Info->Protect = MemoryArea->Protect;
226 Info->AllocationProtect = MemoryArea->Protect;
227 Info->BaseAddress = MemoryArea->StartingAddress;
228 Info->AllocationBase = MemoryArea->StartingAddress;
229 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
230 (ULONG_PTR)MemoryArea->StartingAddress;
231 Status = STATUS_SUCCESS;
232 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
233 break;
234 case MEMORY_AREA_PAGED_POOL:
235 Info->Type = 0;
236 Info->State = MEM_COMMIT;
237 Info->Protect = MemoryArea->Protect;
238 Info->AllocationProtect = MemoryArea->Protect;
239 Info->BaseAddress = MemoryArea->StartingAddress;
240 Info->AllocationBase = MemoryArea->StartingAddress;
241 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
242 (ULONG_PTR)MemoryArea->StartingAddress;
243 Status = STATUS_SUCCESS;
244 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
245 break;
246 default:
247 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
248 Status = STATUS_UNSUCCESSFUL;
249 *ResultLength = 0;
250 }
251 }
252 break;
253 }
254
255 default:
256 {
257 Status = STATUS_INVALID_INFO_CLASS;
258 *ResultLength = 0;
259 break;
260 }
261 }
262
263 MmUnlockAddressSpace(AddressSpace);
264 if (Address < MmSystemRangeStart)
265 {
266 ObDereferenceObject(Process);
267 }
268
269 return Status;
270 }
271
272 /* (tMk 2004.II.4)
273 * FUNCTION:
274 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
275 *
276 */
277 NTSTATUS STDCALL
278 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
279 IN PVOID Address,
280 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
281 OUT PVOID VirtualMemoryInformation,
282 IN ULONG Length,
283 OUT PULONG UnsafeResultLength)
284 {
285 NTSTATUS Status = STATUS_SUCCESS;
286 ULONG ResultLength = 0;
287 KPROCESSOR_MODE PreviousMode;
288 union
289 {
290 MEMORY_BASIC_INFORMATION BasicInfo;
291 }
292 VirtualMemoryInfo;
293
294 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
295 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
296 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
297 VirtualMemoryInformationClass,VirtualMemoryInformation,
298 Length,ResultLength);
299
300 PreviousMode = ExGetPreviousMode();
301
302 if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
303 {
304 _SEH_TRY
305 {
306 ProbeForWriteUlong(UnsafeResultLength);
307 }
308 _SEH_HANDLE
309 {
310 Status = _SEH_GetExceptionCode();
311 }
312 _SEH_END;
313
314 if (!NT_SUCCESS(Status))
315 {
316 return Status;
317 }
318 }
319
320 if (Address >= MmSystemRangeStart)
321 {
322 DPRINT1("Invalid parameter\n");
323 return STATUS_INVALID_PARAMETER;
324 }
325
326 Status = MiQueryVirtualMemory ( ProcessHandle,
327 Address,
328 VirtualMemoryInformationClass,
329 &VirtualMemoryInfo,
330 Length,
331 &ResultLength );
332
333 if (NT_SUCCESS(Status))
334 {
335 if (PreviousMode != KernelMode)
336 {
337 _SEH_TRY
338 {
339 if (ResultLength > 0)
340 {
341 ProbeForWrite(VirtualMemoryInformation,
342 ResultLength,
343 1);
344 RtlCopyMemory(VirtualMemoryInformation,
345 &VirtualMemoryInfo,
346 ResultLength);
347 }
348 if (UnsafeResultLength != NULL)
349 {
350 *UnsafeResultLength = ResultLength;
351 }
352 }
353 _SEH_HANDLE
354 {
355 Status = _SEH_GetExceptionCode();
356 }
357 _SEH_END;
358 }
359 else
360 {
361 if (ResultLength > 0)
362 {
363 RtlCopyMemory(VirtualMemoryInformation,
364 &VirtualMemoryInfo,
365 ResultLength);
366 }
367
368 if (UnsafeResultLength != NULL)
369 {
370 *UnsafeResultLength = ResultLength;
371 }
372 }
373 }
374
375 return(Status);
376 }
377
378
379 NTSTATUS STDCALL
380 MiProtectVirtualMemory(IN PEPROCESS Process,
381 IN OUT PVOID *BaseAddress,
382 IN OUT PULONG NumberOfBytesToProtect,
383 IN ULONG NewAccessProtection,
384 OUT PULONG OldAccessProtection OPTIONAL)
385 {
386 PMEMORY_AREA MemoryArea;
387 PMADDRESS_SPACE AddressSpace;
388 ULONG OldAccessProtection_;
389 NTSTATUS Status;
390
391 *NumberOfBytesToProtect =
392 PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
393 PAGE_ROUND_DOWN(*BaseAddress);
394 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
395
396 AddressSpace = &Process->AddressSpace;
397
398 MmLockAddressSpace(AddressSpace);
399 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
400 if (MemoryArea == NULL)
401 {
402 MmUnlockAddressSpace(AddressSpace);
403 return STATUS_UNSUCCESSFUL;
404 }
405
406 if (OldAccessProtection == NULL)
407 OldAccessProtection = &OldAccessProtection_;
408
409 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
410 {
411 Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
412 *NumberOfBytesToProtect, NewAccessProtection,
413 OldAccessProtection);
414 }
415 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
416 {
417 Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
418 *NumberOfBytesToProtect,
419 NewAccessProtection,
420 OldAccessProtection);
421 }
422 else
423 {
424 /* FIXME: Should we return failure or success in this case? */
425 Status = STATUS_CONFLICTING_ADDRESSES;
426 }
427
428 MmUnlockAddressSpace(AddressSpace);
429
430 return Status;
431 }
432
433
434 /* (tMk 2004.II.5)
435 * FUNCTION:
436 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
437 *
438 */
439 NTSTATUS STDCALL
440 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
441 IN OUT PVOID *UnsafeBaseAddress,
442 IN OUT ULONG *UnsafeNumberOfBytesToProtect,
443 IN ULONG NewAccessProtection,
444 OUT PULONG UnsafeOldAccessProtection)
445 {
446 PEPROCESS Process;
447 ULONG OldAccessProtection;
448 PVOID BaseAddress = NULL;
449 ULONG NumberOfBytesToProtect = 0;
450 KPROCESSOR_MODE PreviousMode;
451 NTSTATUS Status = STATUS_SUCCESS;
452
453 PreviousMode = ExGetPreviousMode();
454
455 if (PreviousMode != KernelMode)
456 {
457 _SEH_TRY
458 {
459 ProbeForWritePointer(UnsafeBaseAddress);
460 ProbeForWriteUlong(UnsafeNumberOfBytesToProtect);
461 ProbeForWriteUlong(UnsafeOldAccessProtection);
462
463 BaseAddress = *UnsafeBaseAddress;
464 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
465 }
466 _SEH_HANDLE
467 {
468 Status = _SEH_GetExceptionCode();
469 }
470 _SEH_END;
471
472 if (!NT_SUCCESS(Status))
473 {
474 return Status;
475 }
476 }
477 else
478 {
479 BaseAddress = *UnsafeBaseAddress;
480 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
481 }
482
483 if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress ||
484 (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress)
485 {
486 /* Don't allow to change the protection of a kernel mode address */
487 return STATUS_INVALID_PARAMETER_2;
488 }
489
490 /* (tMk 2004.II.5) in Microsoft SDK I read:
491 * 'if this parameter is NULL or does not point to a valid variable, the function fails'
492 */
493 if(UnsafeOldAccessProtection == NULL)
494 {
495 return(STATUS_INVALID_PARAMETER);
496 }
497
498 Status = ObReferenceObjectByHandle(ProcessHandle,
499 PROCESS_VM_OPERATION,
500 PsProcessType,
501 UserMode,
502 (PVOID*)(&Process),
503 NULL);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
507 return(Status);
508 }
509
510 Status = MiProtectVirtualMemory(Process,
511 &BaseAddress,
512 &NumberOfBytesToProtect,
513 NewAccessProtection,
514 &OldAccessProtection);
515
516 ObDereferenceObject(Process);
517
518 if (PreviousMode != KernelMode)
519 {
520 _SEH_TRY
521 {
522 *UnsafeOldAccessProtection = OldAccessProtection;
523 *UnsafeBaseAddress = BaseAddress;
524 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
525 }
526 _SEH_HANDLE
527 {
528 Status = _SEH_GetExceptionCode();
529 }
530 _SEH_END;
531 }
532 else
533 {
534 *UnsafeOldAccessProtection = OldAccessProtection;
535 *UnsafeBaseAddress = BaseAddress;
536 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
537 }
538
539 return(Status);
540 }
541
542
543 /* (tMk 2004.II.05)
544 * FUNCTION:
545 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
546 *
547 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
548 */
549 NTSTATUS STDCALL
550 NtReadVirtualMemory(IN HANDLE ProcessHandle,
551 IN PVOID BaseAddress,
552 OUT PVOID Buffer,
553 IN ULONG NumberOfBytesToRead,
554 OUT PULONG NumberOfBytesRead OPTIONAL)
555 {
556 PMDL Mdl;
557 PVOID SystemAddress;
558 KPROCESSOR_MODE PreviousMode;
559 PEPROCESS Process, CurrentProcess;
560 NTSTATUS Status = STATUS_SUCCESS;
561
562 PAGED_CODE();
563
564 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
565 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
566 Buffer,NumberOfBytesToRead);
567
568 if ((ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 < (ULONG_PTR)BaseAddress ||
569 (ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
570 {
571 /* Don't allow to read from kernel space */
572 return STATUS_ACCESS_VIOLATION;
573 }
574
575 PreviousMode = ExGetPreviousMode();
576
577 if (PreviousMode != KernelMode)
578 {
579 if ((ULONG_PTR)Buffer + NumberOfBytesToRead - 1 < (ULONG_PTR)Buffer ||
580 (ULONG_PTR)Buffer + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
581 {
582 /* Don't allow to write into kernel space */
583 return STATUS_ACCESS_VIOLATION;
584 }
585 }
586
587 Status = ObReferenceObjectByHandle(ProcessHandle,
588 PROCESS_VM_READ,
589 NULL,
590 PreviousMode,
591 (PVOID*)(&Process),
592 NULL);
593 if (!NT_SUCCESS(Status))
594 {
595 return(Status);
596 }
597
598 CurrentProcess = PsGetCurrentProcess();
599
600 if(PreviousMode != KernelMode)
601 {
602 _SEH_TRY
603 {
604 if(NumberOfBytesRead != NULL)
605 {
606 ProbeForWriteUlong(NumberOfBytesRead);
607 }
608 }
609 _SEH_HANDLE
610 {
611 Status = _SEH_GetExceptionCode();
612 }
613 _SEH_END;
614
615 if(!NT_SUCCESS(Status))
616 {
617 return Status;
618 }
619 }
620
621
622 if (Process == CurrentProcess)
623 {
624 _SEH_TRY
625 {
626 RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead);
627 }
628 _SEH_HANDLE
629 {
630 Status = _SEH_GetExceptionCode();
631 }
632 _SEH_END;
633 }
634 else
635 {
636 Mdl = MmCreateMdl(NULL,
637 Buffer,
638 NumberOfBytesToRead);
639 if(Mdl == NULL)
640 {
641 ObDereferenceObject(Process);
642 return(STATUS_NO_MEMORY);
643 }
644 _SEH_TRY
645 {
646 MmProbeAndLockPages(Mdl,
647 PreviousMode,
648 IoWriteAccess);
649 }
650 _SEH_HANDLE
651 {
652 Status = _SEH_GetExceptionCode();
653 }
654 _SEH_END;
655
656 if(NT_SUCCESS(Status))
657 {
658 KeAttachProcess(&Process->Pcb);
659
660 SystemAddress = MmGetSystemAddressForMdl(Mdl);
661
662 Status = STATUS_SUCCESS;
663 _SEH_TRY {
664 Status = STATUS_PARTIAL_COPY;
665 RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead);
666 Status = STATUS_SUCCESS;
667 } _SEH_HANDLE {
668 if(Status != STATUS_PARTIAL_COPY)
669 Status = _SEH_GetExceptionCode();
670 } _SEH_END;
671
672 KeDetachProcess();
673
674 if (Mdl->MappedSystemVa != NULL)
675 {
676 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
677 }
678 MmUnlockPages(Mdl);
679 }
680 ExFreePool(Mdl);
681 }
682
683 ObDereferenceObject(Process);
684
685 if((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) &&
686 NumberOfBytesRead != NULL)
687 {
688 _SEH_TRY
689 {
690 *NumberOfBytesRead = NumberOfBytesToRead;
691 }
692 _SEH_HANDLE
693 {
694 Status = _SEH_GetExceptionCode();
695 }
696 _SEH_END;
697 }
698
699 return(Status);
700 }
701
702 /* (tMk 2004.II.05)
703 * FUNCTION: THIS function doesn't make a sense...
704 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
705 */
706 NTSTATUS STDCALL
707 NtUnlockVirtualMemory(HANDLE ProcessHandle,
708 PVOID BaseAddress,
709 ULONG NumberOfBytesToUnlock,
710 PULONG NumberOfBytesUnlocked OPTIONAL)
711 {
712 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
713 // other functions as a template and made a few intelligent guesses...
714
715 NTSTATUS Status;
716 PMDL Mdl;
717 PEPROCESS Process;
718
719 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
720 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
721 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
722
723 Status = ObReferenceObjectByHandle(ProcessHandle,
724 PROCESS_VM_WRITE,
725 NULL,
726 UserMode,
727 (PVOID*)(&Process),
728 NULL);
729 if (!NT_SUCCESS(Status))
730 {
731 return(Status);
732 }
733
734 Mdl = MmCreateMdl(NULL,
735 BaseAddress,
736 NumberOfBytesToUnlock);
737 if(Mdl == NULL)
738 {
739 ObDereferenceObject(Process);
740 return(STATUS_NO_MEMORY);
741 }
742
743 ObDereferenceObject(Process);
744
745 if (Mdl->MappedSystemVa != NULL)
746 {
747 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
748 }
749 MmUnlockPages(Mdl);
750 ExFreePool(Mdl);
751
752 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
753
754 return(STATUS_SUCCESS);
755 }
756
757
758 /* (tMk 2004.II.05)
759 * FUNCTION:
760 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
761 *
762 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
763 */
764 NTSTATUS STDCALL
765 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
766 IN PVOID BaseAddress,
767 IN PVOID Buffer,
768 IN ULONG NumberOfBytesToWrite,
769 OUT PULONG NumberOfBytesWritten OPTIONAL)
770 {
771 PMDL Mdl;
772 PVOID SystemAddress;
773 PEPROCESS Process;
774 KPROCESSOR_MODE PreviousMode;
775 NTSTATUS CopyStatus, Status = STATUS_SUCCESS;
776
777 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
778 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
779 Buffer,NumberOfBytesToWrite);
780
781 if ((ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 < (ULONG_PTR)BaseAddress ||
782 (ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
783 {
784 /* Don't allow to write into kernel space */
785 return STATUS_ACCESS_VIOLATION;
786 }
787
788 PreviousMode = ExGetPreviousMode();
789
790 if (PreviousMode != KernelMode)
791 {
792 if ((ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 < (ULONG_PTR)Buffer ||
793 (ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
794 {
795 /* Don't allow to read from kernel space */
796 return STATUS_ACCESS_VIOLATION;
797 }
798 if (NumberOfBytesWritten != NULL)
799 {
800 _SEH_TRY
801 {
802 ProbeForWriteUlong(NumberOfBytesWritten);
803 }
804 _SEH_HANDLE
805 {
806 Status = _SEH_GetExceptionCode();
807 }
808 _SEH_END;
809
810 if (!NT_SUCCESS(Status))
811 {
812 return Status;
813 }
814 }
815 }
816
817 Status = ObReferenceObjectByHandle(ProcessHandle,
818 PROCESS_VM_WRITE,
819 NULL,
820 UserMode,
821 (PVOID*)(&Process),
822 NULL);
823 if (!NT_SUCCESS(Status))
824 {
825 return(Status);
826 }
827
828 CopyStatus = STATUS_SUCCESS;
829
830 /* Write memory */
831 if (Process == PsGetCurrentProcess())
832 {
833 if (PreviousMode != KernelMode)
834 {
835 _SEH_TRY
836 {
837 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
838 }
839 _SEH_HANDLE
840 {
841 CopyStatus = _SEH_GetExceptionCode();
842 }
843 _SEH_END;
844 }
845 else
846 {
847 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
848 }
849 }
850 else
851 {
852 /* Create MDL describing the source buffer. */
853 Mdl = MmCreateMdl(NULL,
854 Buffer,
855 NumberOfBytesToWrite);
856 if(Mdl == NULL)
857 {
858 ObDereferenceObject(Process);
859 return(STATUS_NO_MEMORY);
860 }
861 _SEH_TRY
862 {
863 /* Map the MDL. */
864 MmProbeAndLockPages(Mdl,
865 UserMode,
866 IoReadAccess);
867 }
868 _SEH_HANDLE
869 {
870 CopyStatus = _SEH_GetExceptionCode();
871 }
872 _SEH_END;
873
874 if (NT_SUCCESS(CopyStatus))
875 {
876 /* Copy memory from the mapped MDL into the target buffer. */
877 KeAttachProcess(&Process->Pcb);
878
879 SystemAddress = MmGetSystemAddressForMdl(Mdl);
880 if (PreviousMode != KernelMode)
881 {
882 _SEH_TRY
883 {
884 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
885 }
886 _SEH_HANDLE
887 {
888 CopyStatus = _SEH_GetExceptionCode();
889 }
890 _SEH_END;
891 }
892 else
893 {
894 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
895 }
896
897 KeDetachProcess();
898 }
899
900 /* Free the MDL. */
901 if (Mdl->MappedSystemVa != NULL)
902 {
903 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
904 }
905 MmUnlockPages(Mdl);
906 ExFreePool(Mdl);
907 }
908 ObDereferenceObject(Process);
909
910 if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL)
911 {
912 if (PreviousMode != KernelMode)
913 {
914 _SEH_TRY
915 {
916 *NumberOfBytesWritten = NumberOfBytesToWrite;
917 }
918 _SEH_HANDLE
919 {
920 Status = _SEH_GetExceptionCode();
921 }
922 _SEH_END;
923 }
924 else
925 {
926 *NumberOfBytesWritten = NumberOfBytesToWrite;
927 }
928 }
929
930 return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus);
931 }
932
933 /*
934 * @unimplemented
935 */
936
937 PVOID
938 STDCALL
939 MmGetVirtualForPhysical (
940 IN PHYSICAL_ADDRESS PhysicalAddress
941 )
942 {
943 UNIMPLEMENTED;
944 return 0;
945 }
946
947 /* FUNCTION:
948 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
949 * @unimplemented
950 */
951 PVOID STDCALL
952 MmSecureVirtualMemory (PVOID Address,
953 SIZE_T Length,
954 ULONG Mode)
955 {
956 /* Only works for user space */
957 if (MmHighestUserAddress < Address)
958 {
959 return NULL;
960 }
961
962 UNIMPLEMENTED;
963
964 return 0;
965 }
966
967
968 /* FUNCTION:
969 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
970 * @unimplemented
971 */
972 VOID STDCALL
973 MmUnsecureVirtualMemory(PVOID SecureMem)
974 {
975 if (NULL == SecureMem)
976 {
977 return;
978 }
979
980 UNIMPLEMENTED;
981 }
982
983
984 /*
985 * @implemented
986 */
987 VOID STDCALL
988 ProbeForRead (IN CONST VOID *Address,
989 IN ULONG Length,
990 IN ULONG Alignment)
991 {
992 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
993
994 if (Length == 0)
995 return;
996
997 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
998 {
999 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
1000 }
1001 else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
1002 (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
1003 {
1004 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1005 }
1006 }
1007
1008
1009 /*
1010 * @implemented
1011 */
1012 VOID STDCALL
1013 ProbeForWrite (IN CONST VOID *Address,
1014 IN ULONG Length,
1015 IN ULONG Alignment)
1016 {
1017 volatile CHAR *Current;
1018 PCHAR Last;
1019
1020 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
1021
1022 if (Length == 0)
1023 return;
1024
1025 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
1026 {
1027 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
1028 }
1029
1030 Last = (CHAR*)((ULONG_PTR)Address + Length - 1);
1031 if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
1032 (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress)
1033 {
1034 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1035 }
1036
1037 /* Check for accessible pages */
1038 Current = (CHAR*)Address;
1039 *Current = *Current;
1040 Current = (PCHAR)((ULONG_PTR)PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
1041 while (Current <= Last)
1042 {
1043 *Current = *Current;
1044 Current = (CHAR*)((ULONG_PTR)Current + PAGE_SIZE);
1045 }
1046 }
1047
1048 /* EOF */