mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 00:31:27 +00:00
[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:
parent
1afef0ace6
commit
cf28a01e5e
3 changed files with 228 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue