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