[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.
.
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

View file

@ -620,10 +620,28 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
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

View file

@ -31,6 +31,150 @@ BOOLEAN MmProtectFreedNonPagedPool;
/* 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
NTAPI
MiInitializeNonPagedPoolThresholds(VOID)
@ -245,7 +389,7 @@ MiAllocatePoolPages(IN POOL_TYPE PoolType,
//
// Handle paged pool
//
if (PoolType == PagedPool)
if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool)
{
//
// Lock the paged pool mutex
@ -755,12 +899,21 @@ MiFreePoolPages(IN PVOID StartingVa)
}
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 @@ MiFreePoolPages(IN PVOID StartingVa)
(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 @@ MiFreePoolPages(IN PVOID StartingVa)
// 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 @@ MiFreePoolPages(IN PVOID StartingVa)
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 @@ MiFreePoolPages(IN PVOID StartingVa)
//
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 @@ MiFreePoolPages(IN PVOID StartingVa)
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 @@ MiFreePoolPages(IN PVOID StartingVa)
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);
}
//
@ -928,6 +1099,13 @@ MiFreePoolPages(IN PVOID StartingVa)
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
//