diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index 02e72870cda..f2f39f9e2d2 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -96,6 +96,7 @@ C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE); // // Protection Bits part of the internal memory manager Protection Mask, from: // http://reactos.org/wiki/Techwiki:Memory_management_in_the_Windows_XP_kernel +// https://www.reactos.org/wiki/Techwiki:Memory_Protection_constants // and public assertions. // #define MM_ZERO_ACCESS 0 @@ -106,9 +107,20 @@ C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE); #define MM_WRITECOPY 5 #define MM_EXECUTE_READWRITE 6 #define MM_EXECUTE_WRITECOPY 7 -#define MM_NOCACHE 8 -#define MM_DECOMMIT 0x10 -#define MM_NOACCESS (MM_DECOMMIT | MM_NOCACHE) + +// +// These are flags on top of the actual protection mask +// +#define MM_NOCACHE 0x08 +#define MM_GUARDPAGE 0x10 +#define MM_WRITECOMBINE 0x18 + +// +// These are special cases +// +#define MM_DECOMMIT (MM_ZERO_ACCESS | MM_GUARDPAGE) +#define MM_NOACCESS (MM_ZERO_ACCESS | MM_WRITECOMBINE) +#define MM_OUTSWAPPED_KSTACK (MM_EXECUTE_WRITECOPY | MM_WRITECOMBINE) #define MM_INVALID_PROTECTION 0xFFFFFFFF // @@ -576,6 +588,7 @@ typedef struct _MM_SESSION_SPACE LONG ImageLoadingCount; } MM_SESSION_SPACE, *PMM_SESSION_SPACE; +static const MMPTE MmZeroPte = {{0}}; extern PMM_SESSION_SPACE MmSessionSpace; extern MMPTE HyperTemplatePte; extern MMPDE ValidKernelPde; diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index ae1158e61a3..29a3c197258 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -112,12 +112,41 @@ MiCheckForUserStackOverflow(IN PVOID Address, return STATUS_STACK_OVERFLOW; } +FORCEINLINE +BOOLEAN +MiIsAccessAllowed( + _In_ ULONG ProtectionMask, + _In_ BOOLEAN Write, + _In_ BOOLEAN Execute) +{ + #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \ + (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \ + ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7) + static const UCHAR MiAccessAllowedMask[2][2] = + { + { // Protect 0 1 2 3 4 5 6 7 + _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ + _BYTE_MASK(0, 0, 1, 1, 0, 0, 1, 1), // EXECUTE READ + }, + { + _BYTE_MASK(0, 0, 0, 0, 1, 1, 1, 1), // WRITE + _BYTE_MASK(0, 0, 0, 0, 0, 0, 1, 1), // EXECUTE WRITE + } + }; + + /* We want only the low 3 bits */ + ProtectionMask &= 7; + + /* Look it up in the table */ + return (MiAccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1; +} + NTSTATUS NTAPI MiAccessCheck(IN PMMPTE PointerPte, IN BOOLEAN StoreInstruction, IN KPROCESSOR_MODE PreviousMode, - IN ULONG_PTR ProtectionCode, + IN ULONG_PTR ProtectionMask, IN PVOID TrapFrame, IN BOOLEAN LockHeld) { @@ -151,20 +180,17 @@ MiAccessCheck(IN PMMPTE PointerPte, return STATUS_SUCCESS; } - /* Convert any fault flag to 1 only */ - if (StoreInstruction) StoreInstruction = 1; - -#if 0 /* Check if the protection on the page allows what is being attempted */ - if ((MmReadWrite[Protection] - StoreInstruction) < 10) + if (!MiIsAccessAllowed(ProtectionMask, StoreInstruction, FALSE)) { return STATUS_ACCESS_VIOLATION; } -#endif /* Check if this is a guard page */ - if (ProtectionCode & MM_DECOMMIT) + if (ProtectionMask & MM_GUARDPAGE) { + NT_ASSERT(ProtectionMask != MM_DECOMMIT); + /* Attached processes can't expand their stack */ if (KeIsAttachedProcess()) return STATUS_ACCESS_VIOLATION; @@ -173,7 +199,9 @@ MiAccessCheck(IN PMMPTE PointerPte, (TempPte.u.Soft.Prototype == 0)) == FALSE); /* Remove the guard page bit, and return a guard page violation */ - PointerPte->u.Soft.Protection = ProtectionCode & ~MM_DECOMMIT; + TempPte.u.Soft.Protection = ProtectionMask & ~MM_GUARDPAGE; + NT_ASSERT(TempPte.u.Long != 0); + MI_WRITE_INVALID_PTE(PointerPte, TempPte); return STATUS_GUARD_PAGE_VIOLATION; } @@ -951,6 +979,9 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction, return STATUS_ACCESS_VIOLATION; } + /* There is no such thing as a decommitted prototype PTE */ + NT_ASSERT(TempPte.u.Long != MmDecommittedPte.u.Long); + /* Check for access rights on the PTE proper */ PteContents = *PointerPte; if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) @@ -1863,10 +1894,14 @@ UserFault: } /* Is this a guard page? */ - if (ProtectionCode & MM_DECOMMIT) + if (ProtectionCode & MM_GUARDPAGE) { + /* The VAD protection cannot be MM_DECOMMIT! */ + NT_ASSERT(ProtectionCode != MM_DECOMMIT); + /* Remove the bit */ - PointerPte->u.Soft.Protection = ProtectionCode & ~MM_DECOMMIT; + TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE; + MI_WRITE_INVALID_PTE(PointerPte, TempPte); /* Not supported */ ASSERT(ProtoPte == NULL); @@ -1892,7 +1927,8 @@ UserFault: else { /* No, create a new PTE. First, write the protection */ - PointerPte->u.Soft.Protection = ProtectionCode; + TempPte.u.Soft.Protection = ProtectionCode; + MI_WRITE_INVALID_PTE(PointerPte, TempPte); } /* Lock the PFN database since we're going to grab a page */ @@ -1972,6 +2008,7 @@ UserFault: /* Write the prototype PTE */ TempPte = PrototypePte; TempPte.u.Soft.Protection = ProtectionCode; + NT_ASSERT(TempPte.u.Long != 0); MI_WRITE_INVALID_PTE(PointerPte, TempPte); } else diff --git a/reactos/ntoskrnl/mm/ARM3/section.c b/reactos/ntoskrnl/mm/ARM3/section.c index f20538bcf04..403376d3d51 100644 --- a/reactos/ntoskrnl/mm/ARM3/section.c +++ b/reactos/ntoskrnl/mm/ARM3/section.c @@ -198,7 +198,7 @@ MiMakeProtectionMask(IN ULONG Protect) } /* This actually turns on guard page in this scenario! */ - ProtectMask |= MM_DECOMMIT; + ProtectMask |= MM_GUARDPAGE; } /* Check for nocache option */ diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c index 3b350e56473..d8d3eadcb4f 100644 --- a/reactos/ntoskrnl/mm/ARM3/virtual.c +++ b/reactos/ntoskrnl/mm/ARM3/virtual.c @@ -350,7 +350,7 @@ MiDeleteSystemPageableVm(IN PMMPTE PointerPte, KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); /* Destroy the PTE */ - PointerPte->u.Long = 0; + MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); } /* Actual legitimate pages */ @@ -368,7 +368,7 @@ MiDeleteSystemPageableVm(IN PMMPTE PointerPte, ASSERT(PointerPte->u.Soft.PageFileHigh == 0); /* Destroy the PTE */ - PointerPte->u.Long = 0; + MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); } /* Keep going */ @@ -486,7 +486,7 @@ MiDeletePte(IN PMMPTE PointerPte, } /* Destroy the PTE and flush the TLB */ - PointerPte->u.Long = 0; + MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); KeFlushCurrentTb(); } @@ -618,7 +618,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, (TempPte.u.Soft.Prototype == 1)) { /* Just nuke it */ - PointerPte->u.Long = 0; + MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); } else { @@ -632,7 +632,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, else { /* The PTE was never mapped, just nuke it here */ - PointerPte->u.Long = 0; + MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); } } @@ -2113,7 +2113,8 @@ MiProtectVirtualMemory(IN PEPROCESS Process, ASSERT(PteContents.u.Soft.Transition == 0); /* The PTE is already demand-zero, just update the protection mask */ - PointerPte->u.Soft.Protection = ProtectionMask; + PteContents.u.Soft.Protection = ProtectionMask; + MI_WRITE_INVALID_PTE(PointerPte, PteContents); ASSERT(PointerPte->u.Long != 0); }