mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 16:51:18 +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.
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,10 +944,12 @@ 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;
|
||||||
|
|
||||||
|
/* Remove the item from the list, depending if pool is protected */
|
||||||
|
MmProtectFreedNonPagedPool ?
|
||||||
|
MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
|
||||||
RemoveEntryList(&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,9 +1026,9 @@ 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);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -871,9 +1042,9 @@ 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,9 +1073,9 @@ 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
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue