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