Add bounds checking and implement reclamation for large expansion pool allocations
All checks were successful
Builds / ExectOS (i686, release) (push) Successful in 27s
Builds / ExectOS (amd64, release) (push) Successful in 25s
Builds / ExectOS (i686, debug) (push) Successful in 37s
Builds / ExectOS (amd64, debug) (push) Successful in 38s

This commit is contained in:
2026-03-24 23:00:28 +01:00
parent 92986e1386
commit adff181f5a

View File

@@ -747,8 +747,9 @@ MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress,
OUT PPFN_NUMBER PagesFreed) OUT PPFN_NUMBER PagesFreed)
{ {
PMMFREE_POOL_ENTRY FreePage, NextPage, LastPage; PMMFREE_POOL_ENTRY FreePage, NextPage, LastPage;
PFN_COUNT FreePages, Pages;
PMMMEMORY_LAYOUT MemoryLayout; PMMMEMORY_LAYOUT MemoryLayout;
PFN_COUNT FreePages, Pages;
PFN_NUMBER PageFrameNumber;
PMMPFN Pfn, FirstPfn; PMMPFN Pfn, FirstPfn;
PMMPTE PointerPte; PMMPTE PointerPte;
ULONG Index; ULONG Index;
@@ -760,11 +761,21 @@ MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress,
PointerPte = MM::Paging::GetPteAddress(VirtualAddress); PointerPte = MM::Paging::GetPteAddress(VirtualAddress);
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte)); Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
/* Verify that the address is within the non-paged pool */
if((VirtualAddress < MemoryLayout->NonPagedPoolStart ||
VirtualAddress >= MemoryLayout->NonPagedPoolEnd) &&
(VirtualAddress < MemoryLayout->NonPagedExpansionPoolStart ||
VirtualAddress >= MemoryLayout->NonPagedExpansionPoolEnd))
{
/* Address does not belong to the non-paged pool, raise kernel panic */
KE::Crash::Panic(0xC2, 0x43, (ULONG_PTR)VirtualAddress, 0, 0);
}
/* Basic sanity check to prevent double-frees or freeing unallocated memory */ /* Basic sanity check to prevent double-frees or freeing unallocated memory */
if(Pfn->u3.e1.ReadInProgress == 0) if(Pfn->u3.e1.ReadInProgress == 0)
{ {
/* Memory is not marked as the start of an allocation, return error */ /* Address is not an allocation head, raise kernel panic */
return STATUS_INVALID_PARAMETER; KE::Crash::Panic(0xC2, 0x41, (ULONG_PTR)VirtualAddress, (ULONG_PTR)Pfn, 0);
} }
/* Save the first PFN entry and initialize the allocation page counter */ /* Save the first PFN entry and initialize the allocation page counter */
@@ -793,6 +804,49 @@ MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress,
FirstPfn->u3.e1.ReadInProgress = 0; FirstPfn->u3.e1.ReadInProgress = 0;
Pfn->u3.e1.WriteInProgress = 0; Pfn->u3.e1.WriteInProgress = 0;
/* Check if the address belongs to the non-paged expansion pool */
if(VirtualAddress >= MemoryLayout->NonPagedExpansionPoolStart)
{
/* Check if the allocation spans more than 3 pages and should be reclaimed */
if(Pages > 3)
{
/* Get the first PTE of the allocation and iterate over all pages */
PointerPte = MM::Paging::GetPteAddress(VirtualAddress);
for(Index = 0; Index < Pages; Index++)
{
/* Get the page frame number from the PTE */
PageFrameNumber = MM::Paging::GetPageFrameNumber(PointerPte);
Pfn = MM::Pfn::GetPfnEntry(PageFrameNumber);
/* Clear PFN shared count */
Pfn->u2.ShareCount = 0;
/* Decrement the reference count of the page table */
MM::Pfn::DecrementReferenceCount(Pfn, PageFrameNumber, FALSE);
/* Clear the PTE address and invalidate the PTE */
Pfn->PteAddress = NULLPTR;
MM::Paging::ClearPte(PointerPte);
/* Get the next PTE */
PointerPte = MM::Paging::GetNextPte(PointerPte);
}
/* Release reserved system PTEs back to the pool */
MM::Pte::ReleaseSystemPtes(MM::Paging::GetPteAddress(VirtualAddress), Pages, NonPagedPoolExpansion);
/* Check if a page count was requested */
if(PagesFreed != NULLPTR)
{
/* Return the number of pages freed */
*PagesFreed = FreePages;
}
/* Return success */
return STATUS_SUCCESS;
}
}
/* Get the next PTE */ /* Get the next PTE */
PointerPte = MM::Paging::GetNextPte(PointerPte); PointerPte = MM::Paging::GetNextPte(PointerPte);
@@ -807,12 +861,12 @@ MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress,
/* Check if the PTE is valid */ /* Check if the PTE is valid */
if(MM::Paging::PteValid(PointerPte)) if(MM::Paging::PteValid(PointerPte))
{ {
/* Get the PFN entry for the page laying in either the expansion or initial nonpaged pool */ /* Get the PFN entry for the page laying in either the expansion or initial non-paged pool */
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte)); Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
} }
else else
{ {
/* Ignore the last page of the expansion nonpaged pool */ /* Ignore the last page of the non-paged expansion pool */
Pfn = NULLPTR; Pfn = NULLPTR;
} }
} }