From cbc4cfeed6a6c6f93d1f5e60abb9dd254c38c98f Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 13 Nov 2017 19:00:31 +0100 Subject: [PATCH] [NTOS:EX] Fix handle table code for x64. Based on patch by Ivan Labutin. See PR #115 --- ntoskrnl/ex/handle.c | 64 ++++++++++++++++++---------------- ntoskrnl/include/internal/ex.h | 20 ++++++----- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/ntoskrnl/ex/handle.c b/ntoskrnl/ex/handle.c index b9732f3639d..5c26ccdca86 100644 --- a/ntoskrnl/ex/handle.c +++ b/ntoskrnl/ex/handle.c @@ -18,6 +18,7 @@ LIST_ENTRY HandleTableListHead; EX_PUSH_LOCK HandleTableListLock; #define SizeOfHandle(x) (sizeof(HANDLE) * (x)) +#define INDEX_TO_HANDLE_VALUE(x) ((x) << HANDLE_TAG_BITS) /* PRIVATE FUNCTIONS *********************************************************/ @@ -67,12 +68,14 @@ ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, /* Get the mid level pointer array */ PointerArray = PointerArray[Handle.HighIndex]; + ASSERT(PointerArray != NULL); /* Fall through */ case 1: /* Get the handle array */ HandleArray = PointerArray[Handle.MidIndex]; + ASSERT(HandleArray != NULL); /* Fall through */ case 0: @@ -255,8 +258,8 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, IN EXHANDLE Handle, IN PHANDLE_TABLE_ENTRY HandleTableEntry) { - ULONG OldValue, NewValue, *Free; - ULONG i; + ULONG OldValue, *Free; + ULONG LockIndex; PAGED_CODE(); /* Sanity checks */ @@ -267,16 +270,16 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, InterlockedDecrement(&HandleTable->HandleCount); /* Mark the handle as free */ - NewValue = (ULONG)Handle.Value & ~(SizeOfHandle(1) - 1); + Handle.TagBits = 0; /* Check if we're FIFO */ if (!HandleTable->StrictFIFO) { /* Select a lock index */ - i = (NewValue >> 2) % 4; + LockIndex = Handle.Index % 4; /* Select which entry to use */ - Free = (HandleTable->HandleTableLock[i].Locked) ? + Free = (HandleTable->HandleTableLock[LockIndex].Locked) ? &HandleTable->FirstFree : &HandleTable->LastFree; } else @@ -290,8 +293,8 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, { /* Get the current value and write */ OldValue = *Free; - HandleTableEntry->NextFreeTableEntry = (ULONG)OldValue; - if (InterlockedCompareExchange((PLONG) Free, NewValue, OldValue) == OldValue) + HandleTableEntry->NextFreeTableEntry = OldValue; + if (InterlockedCompareExchange((PLONG)Free, Handle.AsULONG, OldValue) == OldValue) { /* Break out, we're done. Make sure the handle value makes sense */ ASSERT((OldValue & FREE_HANDLE_MASK) < @@ -354,7 +357,7 @@ ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL, { /* Set up the free data */ HandleEntry->Value = 0; - HandleEntry->NextFreeTableEntry = (i + 1) * SizeOfHandle(1); + HandleEntry->NextFreeTableEntry = INDEX_TO_HANDLE_VALUE(i + 1); /* Move to the next entry */ HandleEntry++; @@ -363,11 +366,11 @@ ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL, /* Terminate the last entry */ HandleEntry->Value = 0; HandleEntry->NextFreeTableEntry = 0; - HandleTable->FirstFree = SizeOfHandle(1); + HandleTable->FirstFree = INDEX_TO_HANDLE_VALUE(1); } /* Set the next handle needing pool after our allocated page from above */ - HandleTable->NextHandleNeedingPool = LOW_LEVEL_ENTRIES * SizeOfHandle(1); + HandleTable->NextHandleNeedingPool = INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES); /* Setup the rest of the handle table data */ HandleTable->QuotaProcess = Process; @@ -409,12 +412,12 @@ ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable, { /* Go to the next entry and the base entry */ HandleEntry++; - Base = HandleTable->NextHandleNeedingPool + SizeOfHandle(2); + Base = HandleTable->NextHandleNeedingPool + INDEX_TO_HANDLE_VALUE(2); /* Loop each entry */ for (i = Base; - i < Base + SizeOfHandle(LOW_LEVEL_ENTRIES - 2); - i += SizeOfHandle(1)) + i < Base + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES - 2); + i += INDEX_TO_HANDLE_VALUE(1)) { /* Free this entry and move on to the next one */ HandleEntry->NextFreeTableEntry = i; @@ -494,7 +497,7 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, /* Get if the next index can fit in the table */ i = HandleTable->NextHandleNeedingPool / - SizeOfHandle(LOW_LEVEL_ENTRIES); + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES); if (i < MID_LEVEL_ENTRIES) { /* We need to allocate a new table */ @@ -539,7 +542,7 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, ThirdLevel = (PVOID)TableBase; /* Get the index and check if it can fit */ - i = HandleTable->NextHandleNeedingPool / SizeOfHandle(MAX_MID_INDEX); + i = HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(MAX_MID_INDEX); if (i >= HIGH_LEVEL_ENTRIES) return FALSE; /* Check if there's no mid-level table */ @@ -556,8 +559,8 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, else { /* We have one, check at which index we should insert our entry */ - Index = (HandleTable->NextHandleNeedingPool / SizeOfHandle(1)) - - i * MAX_MID_INDEX; + Index = (HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(1)) - + i * MAX_MID_INDEX; j = Index / LOW_LEVEL_ENTRIES; /* Allocate a new low level */ @@ -577,13 +580,13 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, /* Update the index of the next handle */ Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool, - SizeOfHandle(LOW_LEVEL_ENTRIES)); + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); /* Check if need to initialize the table */ if (DoInit) { /* Create a new index number */ - Index += SizeOfHandle(1); + Index += INDEX_TO_HANDLE_VALUE(1); /* Start free index change loop */ for (;;) @@ -646,7 +649,7 @@ ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, { ULONG OldValue, NewValue, NewValue1; PHANDLE_TABLE_ENTRY Entry; - EXHANDLE Handle; + EXHANDLE Handle, OldHandle; BOOLEAN Result; ULONG i; @@ -709,7 +712,8 @@ ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, Entry = ExpLookupHandleTableEntry(HandleTable, Handle); /* Get an available lock and acquire it */ - i = ((OldValue & FREE_HANDLE_MASK) >> 2) % 4; + OldHandle.Value = OldValue; + i = OldHandle.Index % 4; KeEnterCriticalRegion(); ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]); @@ -1063,7 +1067,7 @@ ExDupHandleTable(IN PEPROCESS Process, NewTable->FirstFree = 0; /* Setup the first handle value */ - Handle.Value = SizeOfHandle(1); + Handle.Value = INDEX_TO_HANDLE_VALUE(1); /* Enter a critical region and lookup the new entry */ KeEnterCriticalRegion(); @@ -1125,13 +1129,13 @@ ExDupHandleTable(IN PEPROCESS Process, } /* Increase the handle value and move to the next entry */ - Handle.Value += SizeOfHandle(1); + Handle.Value += INDEX_TO_HANDLE_VALUE(1); NewEntry++; HandleTableEntry++; - } while (Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES)); + } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); /* We're done, skip the last entry */ - Handle.Value += SizeOfHandle(1); + Handle.Value += INDEX_TO_HANDLE_VALUE(1); } /* Acquire the table lock and insert this new table into the list */ @@ -1198,7 +1202,7 @@ ExSweepHandleTable(IN PHANDLE_TABLE HandleTable, PAGED_CODE(); /* Set the initial value and loop the entries */ - Handle.Value = SizeOfHandle(1); + Handle.Value = INDEX_TO_HANDLE_VALUE(1); while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) { /* Loop each handle */ @@ -1214,12 +1218,12 @@ ExSweepHandleTable(IN PHANDLE_TABLE HandleTable, } /* Go to the next handle and entry */ - Handle.Value += SizeOfHandle(1); + Handle.Value += INDEX_TO_HANDLE_VALUE(1); HandleTableEntry++; - } while (Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES)); + } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES)); /* Skip past the last entry */ - Handle.Value += SizeOfHandle(1); + Handle.Value += INDEX_TO_HANDLE_VALUE(1); } } @@ -1271,7 +1275,7 @@ ExEnumHandleTable(IN PHANDLE_TABLE HandleTable, } /* Go to the next entry */ - Handle.Value += SizeOfHandle(1); + Handle.Value += INDEX_TO_HANDLE_VALUE(1); } /* Leave the critical region and return callback result */ diff --git a/ntoskrnl/include/internal/ex.h b/ntoskrnl/include/internal/ex.h index 3834249c44a..09ba4648df9 100644 --- a/ntoskrnl/include/internal/ex.h +++ b/ntoskrnl/include/internal/ex.h @@ -68,25 +68,29 @@ VOID NTAPI ExpDebuggerWorker(IN PVOID Context); #define HANDLE_LOW_BITS (PAGE_SHIFT - 3) #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2) #endif -#define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - 31) +#define HANDLE_TAG_BITS (2) +#define HANDLE_INDEX_BITS (HANDLE_LOW_BITS + 2*HANDLE_HIGH_BITS) +#define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - HANDLE_INDEX_BITS - HANDLE_TAG_BITS) typedef union _EXHANDLE { struct { - ULONG_PTR TagBits:2; - ULONG_PTR Index:29; + ULONG_PTR TagBits: HANDLE_TAG_BITS; + ULONG_PTR Index: HANDLE_INDEX_BITS; + ULONG_PTR KernelFlag : KERNEL_FLAG_BITS; }; struct { - ULONG_PTR TagBits2:2; - ULONG_PTR LowIndex:HANDLE_LOW_BITS; - ULONG_PTR MidIndex:HANDLE_HIGH_BITS; - ULONG_PTR HighIndex:HANDLE_HIGH_BITS; - ULONG_PTR KernelFlag:KERNEL_FLAG_BITS; + ULONG_PTR TagBits2: HANDLE_TAG_BITS; + ULONG_PTR LowIndex: HANDLE_LOW_BITS; + ULONG_PTR MidIndex: HANDLE_HIGH_BITS; + ULONG_PTR HighIndex: HANDLE_HIGH_BITS; + ULONG_PTR KernelFlag2: KERNEL_FLAG_BITS; }; HANDLE GenericHandleOverlay; ULONG_PTR Value; + ULONG AsULONG; } EXHANDLE, *PEXHANDLE; typedef struct _ETIMER -- 2.17.1