[NTOS:MM] Make SLIST handling for kernel stacks portable

Kernel stacks that re freed, can be placed on an SLIST for quick reuse. The old code was using a member of the PFN of the last stack page as the SLIST_ENTRY. This relies on the following (non-portable) assumptions:
- A stack always has a PTE associated with it.
- This PTE has a PFN associated with it.
- The PFN has an empty field that can be re-used as an SLIST_ENTRY.
- The PFN has another field that points back to the PTE, which then can be used to get the stack base.

Specifically: On x64 the PFN field is not 16 bytes aligned, so it cannot be used as an SLIST_ENTRY. (In a "usermode kernel" the other assumptions are also invalid).

The new code does what Windows does (and which seems absolutely obvious to do): Place the SLIST_ENTRY directly on the stack.
This commit is contained in:
Timo Kreuzer 2018-02-04 13:30:47 +01:00
parent 6c154c0625
commit dd73d1b6d4

View file

@ -175,6 +175,7 @@ MmDeleteKernelStack(IN PVOID StackBase,
PMMPFN Pfn1, Pfn2; PMMPFN Pfn1, Pfn2;
ULONG i; ULONG i;
KIRQL OldIrql; KIRQL OldIrql;
PSLIST_ENTRY SListEntry;
// //
// This should be the guard page, so decrement by one // This should be the guard page, so decrement by one
@ -189,9 +190,8 @@ MmDeleteKernelStack(IN PVOID StackBase,
{ {
if (ExQueryDepthSList(&MmDeadStackSListHead) < MmMaximumDeadKernelStacks) if (ExQueryDepthSList(&MmDeadStackSListHead) < MmMaximumDeadKernelStacks)
{ {
Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); SListEntry = ((PSLIST_ENTRY)StackBase) - 1;
InterlockedPushEntrySList(&MmDeadStackSListHead, InterlockedPushEntrySList(&MmDeadStackSListHead, SListEntry);
(PSLIST_ENTRY)&Pfn1->u1.NextStackPfn);
return; return;
} }
} }
@ -265,7 +265,7 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
KIRQL OldIrql; KIRQL OldIrql;
PFN_NUMBER PageFrameIndex; PFN_NUMBER PageFrameIndex;
ULONG i; ULONG i;
PMMPFN Pfn1; PSLIST_ENTRY SListEntry;
// //
// Calculate pages needed // Calculate pages needed
@ -286,11 +286,10 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
// //
if (ExQueryDepthSList(&MmDeadStackSListHead)) if (ExQueryDepthSList(&MmDeadStackSListHead))
{ {
Pfn1 = (PMMPFN)InterlockedPopEntrySList(&MmDeadStackSListHead); SListEntry = InterlockedPopEntrySList(&MmDeadStackSListHead);
if (Pfn1) if (SListEntry != NULL)
{ {
PointerPte = Pfn1->PteAddress; BaseAddress = (SListEntry + 1);
BaseAddress = MiPteToAddress(++PointerPte);
return BaseAddress; return BaseAddress;
} }
} }