[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

svn path=/trunk/; revision=48649
This commit is contained in:
Sir Richard 2010-08-29 19:13:08 +00:00
parent 1afef0ace6
commit cf28a01e5e
3 changed files with 228 additions and 22 deletions

View file

@ -1311,6 +1311,16 @@ restart your computer, press F8 to select Advanced Startup Options,
and then select Safe Mode. 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 MessageId=0xC8
Severity=Success Severity=Success
Facility=System Facility=System

View file

@ -620,10 +620,28 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
// /* Check one kind of prototype PTE */
// We don't implement prototype PTEs if (TempPte.u.Soft.Prototype)
// {
ASSERT(TempPte.u.Soft.Prototype == 0); /* 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 // We don't implement transition PTEs

View file

@ -31,6 +31,150 @@ BOOLEAN MmProtectFreedNonPagedPool;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
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 VOID
NTAPI NTAPI
MiInitializeNonPagedPoolThresholds(VOID) MiInitializeNonPagedPoolThresholds(VOID)
@ -245,7 +389,7 @@ MiAllocatePoolPages(IN POOL_TYPE PoolType,
// //
// Handle paged pool // Handle paged pool
// //
if (PoolType == PagedPool) if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool)
{ {
// //
// Lock the paged pool mutex // Lock the paged pool mutex
@ -755,12 +899,21 @@ MiFreePoolPages(IN PVOID StartingVa)
} }
else 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 // Otherwise, our entire allocation must've fit within the initial non
// paged pool, or the expansion nonpaged pool, so get the PFN entry of // paged pool, or the expansion nonpaged pool, so get the PFN entry of
// the next allocation // the next allocation
// //
ASSERT((ULONG_PTR)StartingVa + NumberOfPages <= (ULONG_PTR)MmNonPagedPoolEnd);
if (PointerPte->u.Hard.Valid == 1) if (PointerPte->u.Hard.Valid == 1)
{ {
// //
@ -791,11 +944,13 @@ MiFreePoolPages(IN PVOID StartingVa)
(NumberOfPages << PAGE_SHIFT)); (NumberOfPages << PAGE_SHIFT));
ASSERT(FreeEntry->Owner == FreeEntry); ASSERT(FreeEntry->Owner == FreeEntry);
// /* Consume this entry's pages */
// Consume this entry's pages, and remove it from its free list
//
FreePages += FreeEntry->Size; 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 @@ MiFreePoolPages(IN PVOID StartingVa)
// Otherwise, get the PTE for the page right before our allocation // Otherwise, get the PTE for the page right before our allocation
// //
PointerPte -= NumberOfPages + 1; 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) if (PointerPte->u.Hard.Valid == 1)
{ {
// //
@ -848,6 +1012,13 @@ MiFreePoolPages(IN PVOID StartingVa)
FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa - PAGE_SIZE); FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa - PAGE_SIZE);
FreeEntry = FreeEntry->Owner; 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 // 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 // If it is, we'll want to re-insert it, since we're about to
@ -855,10 +1026,10 @@ MiFreePoolPages(IN PVOID StartingVa)
// //
if (FreeEntry->Size < (MI_MAX_FREE_PAGE_LISTS - 1)) if (FreeEntry->Size < (MI_MAX_FREE_PAGE_LISTS - 1))
{ {
// /* Remove the item from the list, depending if pool is protected */
// Remove the list from where it is now MmProtectFreedNonPagedPool ?
// MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
RemoveEntryList(&FreeEntry->List); RemoveEntryList(&FreeEntry->List);
// //
// Update its size // Update its size
@ -871,10 +1042,10 @@ MiFreePoolPages(IN PVOID StartingVa)
i = (ULONG)(FreeEntry->Size - 1); i = (ULONG)(FreeEntry->Size - 1);
if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
// /* Insert the entry into the free list head, check for prot. pool */
// Do it MmProtectFreedNonPagedPool ?
// MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);
} }
else else
{ {
@ -902,10 +1073,10 @@ MiFreePoolPages(IN PVOID StartingVa)
i = FreeEntry->Size - 1; i = FreeEntry->Size - 1;
if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
// /* Insert the entry into the free list head, check for prot. pool */
// And insert us MmProtectFreedNonPagedPool ?
// MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
InsertTailList (&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);
} }
// //
@ -928,6 +1099,13 @@ MiFreePoolPages(IN PVOID StartingVa)
NextEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + PAGE_SIZE); NextEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + PAGE_SIZE);
} while (NextEntry != LastEntry); } 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 // We're done, release the lock and let the caller know how much we freed
// //