Lock always the address space if we changing the virtual mapping.
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index 08335c9..ffb1257 100644 (file)
@@ -48,6 +48,7 @@
 /* FUNCTIONS *****************************************************************/
 
 NTSTATUS
+NTAPI
 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
                          PMEMORY_AREA MemoryArea,
                          PVOID Address,
@@ -129,6 +130,7 @@ MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
+NTAPI
 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
                        PMEMORY_AREA MemoryArea,
                        PVOID Address,
@@ -169,6 +171,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
     */
    if (!WasDirty)
    {
+      MmLockAddressSpace(AddressSpace);
       MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
       MmDeleteAllRmaps(Page, NULL, NULL);
       if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
@@ -176,6 +179,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
          MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
          MmSetSavedSwapEntryPage(Page, 0);
       }
+      MmUnlockAddressSpace(AddressSpace);
       MmReleasePageMemoryConsumer(MC_USER, Page);
       PageOp->Status = STATUS_SUCCESS;
       KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
@@ -220,8 +224,10 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
     * Otherwise we have succeeded, free the page
     */
    DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
+   MmLockAddressSpace(AddressSpace);
    MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
    MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
+   MmUnlockAddressSpace(AddressSpace);
    MmDeleteAllRmaps(Page, NULL, NULL);
    MmSetSavedSwapEntryPage(Page, 0);
    MmReleasePageMemoryConsumer(MC_USER, Page);
@@ -232,6 +238,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
 }
 
 NTSTATUS
+NTAPI
 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
                                MEMORY_AREA* MemoryArea,
                                PVOID Address,
@@ -555,16 +562,66 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
           *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
           Protect);
 
-   /*
-    * Check the validity of the parameters
-    */
+   /* Check for valid protection flags */
    if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
    {
-      return(STATUS_INVALID_PAGE_PROTECTION);
+      DPRINT1("Invalid page protection\n");
+      return STATUS_INVALID_PAGE_PROTECTION;
+   }
+
+   /* Check for valid Zero bits */
+   if (ZeroBits > 21)
+   {
+      DPRINT1("Too many zero bits\n");
+      return STATUS_INVALID_PARAMETER_3;
+   }
+
+   /* Check for valid Allocation Types */
+   if ((AllocationType &~ (MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
+                           MEM_TOP_DOWN | MEM_WRITE_WATCH)))
+   {
+      DPRINT1("Invalid Allocation Type\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* Check for at least one of these Allocation Types to be set */
+   if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
+   {
+      DPRINT1("No memory allocation base type\n");
+      return STATUS_INVALID_PARAMETER_5;
    }
-   if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+   
+   /* MEM_RESET is an exclusive flag, make sure that is valid too */
+   if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
    {
-      return(STATUS_INVALID_PARAMETER);
+      DPRINT1("MEM_RESET used illegaly\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
+   if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
+   {
+      DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
+      return STATUS_INVALID_PARAMETER_5;
+   }
+
+   /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
+   if (AllocationType & MEM_PHYSICAL)
+   {
+      /* First check for MEM_RESERVE exclusivity */
+      if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL))
+      {
+         DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
+                 "MEM_RESERVE was not present at all\n");
+         return STATUS_INVALID_PARAMETER_5;
+      }
+
+      /* Then make sure PAGE_READWRITE is used */
+      if (Protect != PAGE_READWRITE)
+      {
+         DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
+         return STATUS_INVALID_PAGE_PROTECTION;
+      }
    }
 
    PBaseAddress = *UBaseAddress;
@@ -575,6 +632,39 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
    RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
                 PAGE_ROUND_DOWN(PBaseAddress);
 
+   /* 
+    * We've captured and calculated the data, now do more checks
+    * Yes, MmCreateMemoryArea does similar checks, but they don't return
+    * the right status codes that a caller of this routine would expect.
+    */
+   if (BaseAddress >= MM_HIGHEST_USER_ADDRESS)
+   {
+      DPRINT1("Virtual allocation above User Space\n");
+      return STATUS_INVALID_PARAMETER_2;
+   }
+   if (!RegionSize)
+   {
+      DPRINT1("Region size is invalid\n");
+      return STATUS_INVALID_PARAMETER_4;
+   }
+   if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)BaseAddress) < RegionSize)
+   {
+      DPRINT1("Region size would overflow into kernel-memory\n");
+      return STATUS_INVALID_PARAMETER_4;
+   }
+
+   /* 
+    * Copy on Write is reserved for system use. This case is a certain failure
+    * but there may be other cases...needs more testing
+    */
+   if ((!BaseAddress || (AllocationType & MEM_RESERVE)) && 
+       ((Protect & PAGE_WRITECOPY) || (Protect & PAGE_EXECUTE_WRITECOPY)))
+   {
+      DPRINT1("Copy on write is not supported by VirtualAlloc\n");
+      return STATUS_INVALID_PAGE_PROTECTION;
+   }
+
+
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                       PROCESS_VM_OPERATION,
                                       NULL,
@@ -706,6 +796,7 @@ MmFreeVirtualMemoryPage(PVOID Context,
 }
 
 VOID
+NTAPI
 MmFreeVirtualMemory(PEPROCESS Process,
                     PMEMORY_AREA MemoryArea)
 {
@@ -871,6 +962,7 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
 }
 
 NTSTATUS
+NTAPI
 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
                  PMEMORY_AREA MemoryArea,
                  PVOID BaseAddress,
@@ -909,7 +1001,7 @@ MmQueryAnonMem(PMEMORY_AREA MemoryArea,
    Info->BaseAddress = RegionBase;
    Info->AllocationBase = MemoryArea->StartingAddress;
    Info->AllocationProtect = MemoryArea->Attributes;
-   Info->RegionSize = (char*)RegionBase + Region->Length - (char*)Info->BaseAddress;
+   Info->RegionSize = Region->Length;
    Info->State = Region->Type;
    Info->Protect = Region->Protect;
    Info->Type = MEM_PRIVATE;