[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index 659be42..a7c3dd2 100644 (file)
@@ -420,16 +420,42 @@ MmModifyAttributes(PMMSUPPORT AddressSpace,
             OldProtect != NewProtect)
     {
         ULONG i;
+        PMM_PAGEOP PageOp;
+        PMEMORY_AREA MArea;
+        char* addr = (char*)BaseAddress;
 
         for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
         {
-            if (MmIsPagePresent(Process,
-                        (char*)BaseAddress + (i*PAGE_SIZE)))
+            MArea = MmLocateMemoryAreaByAddress(AddressSpace, addr);
+            do
             {
-                MmSetPageProtect(Process,
-                (char*)BaseAddress + (i*PAGE_SIZE),
-                NewProtect);
+                PageOp = MmGetPageOp(MArea, Process->UniqueProcessId, addr,
+                    NULL, 0, MM_PAGEOP_CHANGEPROTECT, TRUE);
+            } while(PageOp == NULL);
+            
+            /* Should we enable/disable virtual mapping? */
+            if((NewProtect & PAGE_NOACCESS) && 
+                !(OldProtect & PAGE_NOACCESS) && 
+                (MmIsPagePresent(Process, addr)))
+            {
+                /* Set other flags if any */
+                if(NewProtect != PAGE_NOACCESS)
+                    MmSetPageProtect(Process, addr, NewProtect & ~PAGE_NOACCESS);
+                MmDisableVirtualMapping(Process, addr, NULL, NULL);
+            }
+            else if((OldProtect & PAGE_NOACCESS) && !(NewProtect & PAGE_NOACCESS))
+            {
+                MmEnableVirtualMapping(Process, addr);
             }
+            
+            /* Set new protection flags */
+            if(MmIsPagePresent(Process, addr))
+            {
+                MmSetPageProtect(Process, addr, NewProtect);
+            }
+            KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
+            MmReleasePageOp(PageOp);
+            addr += PAGE_SIZE;
         }
     }
 }
@@ -683,6 +709,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
         {
             /* Fail without it */
             DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
+            if (Attached) KeUnstackDetachProcess(&ApcState);
             if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
             return STATUS_PRIVILEGE_NOT_HELD;
         }
@@ -701,6 +728,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
             (Protect & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)))
     {
         DPRINT1("Copy on write is not supported by VirtualAlloc\n");
+        if (Attached) KeUnstackDetachProcess(&ApcState);
+        if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
         return STATUS_INVALID_PAGE_PROTECTION;
     }
 
@@ -1004,11 +1033,11 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
         /* Check for user-mode parameters */
         if (PreviousMode != KernelMode)
         {
-            /* Make sure they are writable */
+            /* Make sure they are writeable */
             ProbeForWritePointer(UBaseAddress);
             ProbeForWriteUlong(URegionSize);
         }
-        
+
         /* Capture their values */
         PBaseAddress = *UBaseAddress;
         PRegionSize = *URegionSize;
@@ -1061,8 +1090,6 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
     }
 
     BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
-    RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
-        PAGE_ROUND_DOWN((PBaseAddress));
 
     AddressSpace = &Process->Vm;
 
@@ -1070,26 +1097,69 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
     if (MemoryArea == NULL)
     {
-        Status = STATUS_UNSUCCESSFUL;
+        DPRINT1("Unable to find memory area from address 0x%p\n", BaseAddress);
+        Status = STATUS_UNABLE_TO_FREE_VM;
         goto unlock_deref_and_return;
     }
 
+    if (PRegionSize != 0)
+    {
+        /* Use the region the caller wanted, rounded to whole pages */
+        RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
+        PAGE_ROUND_DOWN((PBaseAddress));
+    }
+    else
+    {
+        /* The caller wanted the whole memory area */
+        RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                     (ULONG_PTR)MemoryArea->StartingAddress;
+    }
+
     switch (FreeType)
     {
     case MEM_RELEASE:
-        /* We can only free a memory area in one step. */
-        if (MemoryArea->StartingAddress != BaseAddress ||
-                MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
+        /* MEM_RELEASE must be used with the exact base and length
+         * that was returned by NtAllocateVirtualMemory */
+            
+        /* Verify the base address is correct */
+        if (MemoryArea->StartingAddress != BaseAddress)
+        {
+            DPRINT1("Base address is illegal for MEM_RELEASE (0x%p != 0x%p)\n",
+                    MemoryArea->StartingAddress,
+                    BaseAddress);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
+
+        /* Verify the region size is correct */
+        if ((ULONG_PTR)MemoryArea->StartingAddress + RegionSize !=
+            (ULONG_PTR)MemoryArea->EndingAddress)
+        {
+            DPRINT1("Region size is illegal for MEM_RELEASE (0x%x)\n", RegionSize);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            //goto unlock_deref_and_return;
+        }
+
+        if (MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
         {
-            Status = STATUS_UNSUCCESSFUL;
+            DPRINT1("Memory area is not VM\n");
+            Status = STATUS_UNABLE_TO_FREE_VM;
             goto unlock_deref_and_return;
         }
 
         MmFreeVirtualMemory(Process, MemoryArea);
         Status = STATUS_SUCCESS;
-        goto unlock_deref_and_return;
+        break;
 
     case MEM_DECOMMIT:
+        if ((ULONG_PTR)BaseAddress + RegionSize >
+            (ULONG_PTR)MemoryArea->EndingAddress)
+        {
+            DPRINT1("Invald base address (0x%p) and region size (0x%x) for MEM_DECOMMIT\n",
+                    BaseAddress, RegionSize);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
         Status = MmAlterRegion(AddressSpace,
             MemoryArea->StartingAddress,
             (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) ?
@@ -1100,13 +1170,34 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
             MEM_RESERVE,
             PAGE_NOACCESS,
             MmModifyAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("MmAlterRegion failed with status 0x%x\n", Status);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
+        break;
+
+    default:
+        Status = STATUS_NOT_IMPLEMENTED;
         goto unlock_deref_and_return;
     }
 
-    Status = STATUS_NOT_IMPLEMENTED;
-
-    unlock_deref_and_return:
+    /* Enter SEH */
+    _SEH2_TRY
+    {
+        /* Copy rounded values back in success case */
+        *UBaseAddress = BaseAddress;
+        *URegionSize = RegionSize;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Failed to copy values back! (Status: 0x%x)\n", Status);
+    }
+    _SEH2_END;
 
+unlock_deref_and_return:
     MmUnlockAddressSpace(AddressSpace);
     if (Attached) KeUnstackDetachProcess(&ApcState);
     if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);