mirror of
https://github.com/reactos/reactos.git
synced 2024-06-27 08:21:31 +00:00
[0.4.9][NTOS/MM] Properly handle page faults in regions marked with PAGE_NOACCESS or PAGE_GUARD CORE-14694
This was part of the commits for ROSTESTS-110, but much more important: It fixes CORE-14694 "reproducible BSOD 0x1A MEMORY_MANAGEMENT in OllyDbg v2.01" Fix picked from 0.4.11-dev-650-g47ac7a2b28
which also requires me to "Move up MmAlterViewAttributes() for later use in MmNotPresentFaultSectionView()" like it was done in: 0.4.11-dev-649-g47ac7a2b28
Ofc I moved the function up individually in each branch I do port this back to, without modifying the func.
This commit is contained in:
parent
94db51a700
commit
4e0a41bcb8
|
@ -1275,6 +1275,89 @@ MiReadPage(PMEMORY_AREA MemoryArea,
|
|||
}
|
||||
#endif
|
||||
|
||||
static VOID
|
||||
MmAlterViewAttributes(PMMSUPPORT AddressSpace,
|
||||
PVOID BaseAddress,
|
||||
SIZE_T RegionSize,
|
||||
ULONG OldType,
|
||||
ULONG OldProtect,
|
||||
ULONG NewType,
|
||||
ULONG NewProtect)
|
||||
{
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_SECTION_SEGMENT Segment;
|
||||
BOOLEAN DoCOW = FALSE;
|
||||
ULONG i;
|
||||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
||||
ASSERT(MemoryArea != NULL);
|
||||
Segment = MemoryArea->Data.SectionData.Segment;
|
||||
MmLockSectionSegment(Segment);
|
||||
|
||||
if ((Segment->WriteCopy) &&
|
||||
(NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
|
||||
{
|
||||
DoCOW = TRUE;
|
||||
}
|
||||
|
||||
if (OldProtect != NewProtect)
|
||||
{
|
||||
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
|
||||
{
|
||||
SWAPENTRY SwapEntry;
|
||||
PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
|
||||
ULONG Protect = NewProtect;
|
||||
|
||||
/* Wait for a wait entry to disappear */
|
||||
do
|
||||
{
|
||||
MmGetPageFileMapping(Process, Address, &SwapEntry);
|
||||
if (SwapEntry != MM_WAIT_ENTRY)
|
||||
break;
|
||||
MiWaitForPageEvent(Process, Address);
|
||||
}
|
||||
while (TRUE);
|
||||
|
||||
/*
|
||||
* If we doing COW for this segment then check if the page is
|
||||
* already private.
|
||||
*/
|
||||
if (DoCOW && MmIsPagePresent(Process, Address))
|
||||
{
|
||||
LARGE_INTEGER Offset;
|
||||
ULONG_PTR Entry;
|
||||
PFN_NUMBER Page;
|
||||
|
||||
Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
|
||||
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
|
||||
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
|
||||
/*
|
||||
* An MM_WAIT_ENTRY is ok in this case... It'll just count as
|
||||
* IS_SWAP_FROM_SSE and we'll do the right thing.
|
||||
*/
|
||||
Page = MmGetPfnForProcess(Process, Address);
|
||||
|
||||
Protect = PAGE_READONLY;
|
||||
if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
||||
IS_SWAP_FROM_SSE(Entry) ||
|
||||
PFN_FROM_SSE(Entry) != Page)
|
||||
{
|
||||
Protect = NewProtect;
|
||||
}
|
||||
}
|
||||
|
||||
if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
|
||||
{
|
||||
MmSetPageProtect(Process, Address,
|
||||
Protect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MmUnlockSectionSegment(Segment);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
||||
|
@ -1329,6 +1412,29 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
&MemoryArea->Data.SectionData.RegionListHead,
|
||||
Address, NULL);
|
||||
ASSERT(Region != NULL);
|
||||
|
||||
/* Check for a NOACCESS mapping */
|
||||
if (Region->Protect & PAGE_NOACCESS)
|
||||
{
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
|
||||
if (Region->Protect & PAGE_GUARD)
|
||||
{
|
||||
/* Remove it */
|
||||
Status = MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
|
||||
&MemoryArea->Data.SectionData.RegionListHead,
|
||||
Address, PAGE_SIZE, Region->Type, Region->Protect & ~PAGE_GUARD,
|
||||
MmAlterViewAttributes);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Removing PAGE_GUARD protection failed : 0x%08x.\n", Status);
|
||||
}
|
||||
|
||||
return STATUS_GUARD_PAGE_VIOLATION;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the segment
|
||||
*/
|
||||
|
@ -2417,89 +2523,6 @@ MmWritePageSectionView(PMMSUPPORT AddressSpace,
|
|||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static VOID
|
||||
MmAlterViewAttributes(PMMSUPPORT AddressSpace,
|
||||
PVOID BaseAddress,
|
||||
SIZE_T RegionSize,
|
||||
ULONG OldType,
|
||||
ULONG OldProtect,
|
||||
ULONG NewType,
|
||||
ULONG NewProtect)
|
||||
{
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_SECTION_SEGMENT Segment;
|
||||
BOOLEAN DoCOW = FALSE;
|
||||
ULONG i;
|
||||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
||||
ASSERT(MemoryArea != NULL);
|
||||
Segment = MemoryArea->Data.SectionData.Segment;
|
||||
MmLockSectionSegment(Segment);
|
||||
|
||||
if ((Segment->WriteCopy) &&
|
||||
(NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
|
||||
{
|
||||
DoCOW = TRUE;
|
||||
}
|
||||
|
||||
if (OldProtect != NewProtect)
|
||||
{
|
||||
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
|
||||
{
|
||||
SWAPENTRY SwapEntry;
|
||||
PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
|
||||
ULONG Protect = NewProtect;
|
||||
|
||||
/* Wait for a wait entry to disappear */
|
||||
do
|
||||
{
|
||||
MmGetPageFileMapping(Process, Address, &SwapEntry);
|
||||
if (SwapEntry != MM_WAIT_ENTRY)
|
||||
break;
|
||||
MiWaitForPageEvent(Process, Address);
|
||||
}
|
||||
while (TRUE);
|
||||
|
||||
/*
|
||||
* If we doing COW for this segment then check if the page is
|
||||
* already private.
|
||||
*/
|
||||
if (DoCOW && MmIsPagePresent(Process, Address))
|
||||
{
|
||||
LARGE_INTEGER Offset;
|
||||
ULONG_PTR Entry;
|
||||
PFN_NUMBER Page;
|
||||
|
||||
Offset.QuadPart = (ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)
|
||||
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
|
||||
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
|
||||
/*
|
||||
* An MM_WAIT_ENTRY is ok in this case... It'll just count as
|
||||
* IS_SWAP_FROM_SSE and we'll do the right thing.
|
||||
*/
|
||||
Page = MmGetPfnForProcess(Process, Address);
|
||||
|
||||
Protect = PAGE_READONLY;
|
||||
if (Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
|
||||
IS_SWAP_FROM_SSE(Entry) ||
|
||||
PFN_FROM_SSE(Entry) != Page)
|
||||
{
|
||||
Protect = NewProtect;
|
||||
}
|
||||
}
|
||||
|
||||
if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
|
||||
{
|
||||
MmSetPageProtect(Process, Address,
|
||||
Protect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MmUnlockSectionSegment(Segment);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmProtectSectionView(PMMSUPPORT AddressSpace,
|
||||
|
|
Loading…
Reference in a new issue