Author: sir_richard Date: Sun Aug 29 19:13:08 2010 New Revision: 48649
URL: http://svn.reactos.org/svn/reactos?rev=48649&view=rev Log: [NTOS]: Add DRIVER_CAUGHT_MODIFYING_FREED_POOL bugcheck code. [NTOS]: Add support for protected freed nonpaged pool. This is controlled through MmProtectFreedNonPagedPool, which is initialized based on a registry value (see cmdata.c). This is not "Special Pool", but a useful debugging feature Windows implements that we now have too, since I noticed a lot of mj's work was with freed pool access. NB. It's 3AM and I have not tested this, it should be off in trunk by default, you'll need to try turning it on and testing it. Hope it helps. --This line, and those low, will be ignored--
M ntoskrnl/mm/ARM3/pagfault.c M ntoskrnl/mm/ARM3/pool.c M include/reactos/mc/bugcodes.mc
Modified: trunk/reactos/include/reactos/mc/bugcodes.mc trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c trunk/reactos/ntoskrnl/mm/ARM3/pool.c
Modified: trunk/reactos/include/reactos/mc/bugcodes.mc URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/mc/bugcodes... ============================================================================== --- trunk/reactos/include/reactos/mc/bugcodes.mc [iso-8859-1] (original) +++ trunk/reactos/include/reactos/mc/bugcodes.mc [iso-8859-1] Sun Aug 29 19:13:08 2010 @@ -1311,6 +1311,16 @@ and then select Safe Mode. .
+MessageId=0xC6 +Severity=Success +Facility=System +SymbolicName=DRIVER_CAUGHT_MODIFYING_FREED_POOL +Language=English +A device driver attempting to corrupt the system has been caught. +The faulty driver currently on the kernel stack must be replaced +with a working version. +. + MessageId=0xC8 Severity=Success Facility=System
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Sun Aug 29 19:13:08 2010 @@ -620,10 +620,28 @@ return STATUS_SUCCESS; }
- // - // We don't implement prototype PTEs - // - ASSERT(TempPte.u.Soft.Prototype == 0); + /* Check one kind of prototype PTE */ + if (TempPte.u.Soft.Prototype) + { + /* The one used for protected pool... */ + ASSERT(MmProtectFreedNonPagedPool == TRUE); + + /* Make sure protected pool is on, and that this is a pool address */ + if ((MmProtectFreedNonPagedPool) && + (((Address >= MmNonPagedPoolStart) && + (Address < (PVOID)((ULONG_PTR)MmNonPagedPoolStart + + MmSizeOfNonPagedPoolInBytes))) || + ((Address >= MmNonPagedPoolExpansionStart) && + (Address < MmNonPagedPoolEnd)))) + { + /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */ + KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL, + (ULONG_PTR)Address, + StoreInstruction, + Mode, + 4); + } + }
// // We don't implement transition PTEs
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pool.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pool.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/pool.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/pool.c [iso-8859-1] Sun Aug 29 19:13:08 2010 @@ -33,6 +33,150 @@
VOID NTAPI +MiProtectFreeNonPagedPool(IN PVOID VirtualAddress, + IN ULONG PageCount) +{ + PMMPTE PointerPte, LastPte; + MMPTE TempPte; + + /* If pool is physical, can't protect PTEs */ + if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return; + + /* Get PTE pointers and loop */ + PointerPte = MiAddressToPte(VirtualAddress); + LastPte = PointerPte + PageCount; + do + { + /* Capture the PTE for safety */ + TempPte = *PointerPte; + + /* Mark it as an invalid PTE, set proto bit to recognize it as pool */ + TempPte.u.Hard.Valid = 0; + TempPte.u.Soft.Prototype = 1; + MI_WRITE_INVALID_PTE(PointerPte, TempPte); + } while (++PointerPte < LastPte); + + /* Flush the TLB */ + KeFlushEntireTb(TRUE, TRUE); +} + +BOOLEAN +NTAPI +MiUnProtectFreeNonPagedPool(IN PVOID VirtualAddress, + IN ULONG PageCount) +{ + PMMPTE PointerPte; + MMPTE TempPte; + PFN_NUMBER UnprotectedPages = 0; + + /* If pool is physical, can't protect PTEs */ + if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return FALSE; + + /* Get, and capture the PTE */ + PointerPte = MiAddressToPte(VirtualAddress); + TempPte = *PointerPte; + + /* Loop protected PTEs */ + while ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Prototype == 1)) + { + /* Unprotect the PTE */ + TempPte.u.Hard.Valid = 1; + TempPte.u.Soft.Prototype = 0; + MI_WRITE_VALID_PTE(PointerPte, TempPte); + + /* One more page */ + if (++UnprotectedPages == PageCount) break; + + /* Capture next PTE */ + TempPte = *(++PointerPte); + } + + /* Return if any pages were unprotected */ + return UnprotectedPages ? TRUE : FALSE; +} + +VOID +FORCEINLINE +MiProtectedPoolUnProtectLinks(IN PLIST_ENTRY Links, + OUT PVOID* PoolFlink, + OUT PVOID* PoolBlink) +{ + BOOLEAN Safe; + PVOID PoolVa; + + /* Initialize variables */ + *PoolFlink = *PoolBlink = NULL; + + /* Check if the list has entries */ + if (IsListEmpty(Links) == FALSE) + { + /* We are going to need to forward link to do an insert */ + PoolVa = Links->Flink; + + /* So make it safe to access */ + Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1); + if (Safe) PoolFlink = PoolVa; + } + + /* Are we going to need a backward link too? */ + if (Links != Links->Blink) + { + /* Get the head's backward link for the insert */ + PoolVa = Links->Blink; + + /* Make it safe to access */ + Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1); + if (Safe) PoolBlink = PoolVa; + } +} + +VOID +FORCEINLINE +MiProtectedPoolProtectLinks(IN PVOID PoolFlink, + IN PVOID PoolBlink) +{ + /* Reprotect the pages, if they got unprotected earlier */ + if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1); + if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1); +} + +VOID +NTAPI +MiProtectedPoolInsertList(IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry, + IN BOOLEAN Critical) +{ + PVOID PoolFlink, PoolBlink; + + /* Make the list accessible */ + MiProtectedPoolUnProtectLinks(ListHead, &PoolFlink, &PoolBlink); + + /* Now insert in the right position */ + Critical ? InsertHeadList(ListHead, Entry) : InsertTailList(ListHead, Entry); + + /* And reprotect the pages containing the free links */ + MiProtectedPoolProtectLinks(PoolFlink, PoolBlink); +} + +VOID +NTAPI +MiProtectedPoolRemoveEntryList(IN PLIST_ENTRY Entry) +{ + PVOID PoolFlink, PoolBlink; + + /* Make the list accessible */ + MiProtectedPoolUnProtectLinks(Entry, &PoolFlink, &PoolBlink); + + /* Now remove */ + RemoveEntryList(Entry); + + /* And reprotect the pages containing the free links */ + if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1); + if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1); +} + +VOID +NTAPI MiInitializeNonPagedPoolThresholds(VOID) { PFN_NUMBER Size = MmMaximumNonPagedPoolInPages; @@ -245,7 +389,7 @@ // // Handle paged pool // - if (PoolType == PagedPool) + if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool) { // // Lock the paged pool mutex @@ -755,12 +899,21 @@ } else { + /* Sanity check */ + ASSERT((ULONG_PTR)StartingVa + NumberOfPages <= (ULONG_PTR)MmNonPagedPoolEnd); + + /* Check if protected pool is enabled */ + if (MmProtectFreedNonPagedPool) + { + /* The freed block will be merged, it must be made accessible */ + MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0); + } + // // Otherwise, our entire allocation must've fit within the initial non // paged pool, or the expansion nonpaged pool, so get the PFN entry of // the next allocation // - ASSERT((ULONG_PTR)StartingVa + NumberOfPages <= (ULONG_PTR)MmNonPagedPoolEnd); if (PointerPte->u.Hard.Valid == 1) { // @@ -791,11 +944,13 @@ (NumberOfPages << PAGE_SHIFT)); ASSERT(FreeEntry->Owner == FreeEntry);
- // - // Consume this entry's pages, and remove it from its free list - // + /* Consume this entry's pages */ FreePages += FreeEntry->Size; - RemoveEntryList (&FreeEntry->List); + + /* Remove the item from the list, depending if pool is protected */ + MmProtectFreedNonPagedPool ? + MiProtectedPoolRemoveEntryList(&FreeEntry->List) : + RemoveEntryList(&FreeEntry->List); }
// @@ -819,6 +974,15 @@ // Otherwise, get the PTE for the page right before our allocation // PointerPte -= NumberOfPages + 1; + + /* Check if protected pool is enabled */ + if (MmProtectFreedNonPagedPool) + { + /* The freed block will be merged, it must be made accessible */ + MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0); + } + + /* Check if this is valid pool, or a guard page */ if (PointerPte->u.Hard.Valid == 1) { // @@ -848,6 +1012,13 @@ FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa - PAGE_SIZE); FreeEntry = FreeEntry->Owner;
+ /* Check if protected pool is enabled */ + if (MmProtectFreedNonPagedPool) + { + /* The freed block will be merged, it must be made accessible */ + MiUnProtectFreeNonPagedPool(FreeEntry, 0); + } + // // Check if the entry is small enough to be indexed on a free list // If it is, we'll want to re-insert it, since we're about to @@ -855,10 +1026,10 @@ // if (FreeEntry->Size < (MI_MAX_FREE_PAGE_LISTS - 1)) { - // - // Remove the list from where it is now - // - RemoveEntryList(&FreeEntry->List); + /* Remove the item from the list, depending if pool is protected */ + MmProtectFreedNonPagedPool ? + MiProtectedPoolRemoveEntryList(&FreeEntry->List) : + RemoveEntryList(&FreeEntry->List);
// // Update its size @@ -871,10 +1042,10 @@ i = (ULONG)(FreeEntry->Size - 1); if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
- // - // Do it - // - InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); + /* Insert the entry into the free list head, check for prot. pool */ + MmProtectFreedNonPagedPool ? + MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) : + InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); } else { @@ -902,10 +1073,10 @@ i = FreeEntry->Size - 1; if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
- // - // And insert us - // - InsertTailList (&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); + /* Insert the entry into the free list head, check for prot. pool */ + MmProtectFreedNonPagedPool ? + MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) : + InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); }
// @@ -927,6 +1098,13 @@ NextEntry->Owner = FreeEntry; NextEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + PAGE_SIZE); } while (NextEntry != LastEntry); + + /* Is freed non paged pool protected? */ + if (MmProtectFreedNonPagedPool) + { + /* Protect the freed pool! */ + MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size); + }
// // We're done, release the lock and let the caller know how much we freed