Partially fixed up tree after merge from HEAD. More to do.
[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 (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 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 = (PMADDRESS_SPACE)&(Process)->VadRoot;
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 if (Length != 0)
993 {
994 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
995
996 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
997 {
998 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
999 }
1000 else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
1001 (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
1002 {
1003 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1004 }
1005 }
1006 }
1007
1008
1009 /*
1010 * @implemented
1011 */
1012 VOID STDCALL
1013 ProbeForWrite (IN PVOID Address,
1014 IN ULONG Length,
1015 IN ULONG Alignment)
1016 {
1017 volatile CHAR *Current;
1018 PCHAR Last;
1019
1020 if (Length != 0)
1021 {
1022 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
1023
1024 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
1025 {
1026 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
1027 }
1028
1029 Last = (PCHAR)((ULONG_PTR)Address + Length - 1);
1030 if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
1031 (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress)
1032 {
1033 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1034 }
1035
1036 /* Check for accessible pages, do *not* touch any memory outside of the
1037 range!*/
1038 Current = (volatile CHAR*)Address;
1039 Last = (PCHAR)(PAGE_ROUND_DOWN(Last));
1040 do
1041 {
1042 *Current = *Current;
1043 Current = (volatile CHAR*)(PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
1044 } while (Current <= Last);
1045 }
1046 }
1047
1048 /* EOF */