[NTOS:EX] Fix handle table code for x64.

Based on patch by Ivan Labutin. See PR #115
This commit is contained in:
Timo Kreuzer 2017-11-13 19:00:31 +01:00
parent 2daf2391a6
commit cbc4cfeed6
2 changed files with 46 additions and 38 deletions

View file

@ -18,6 +18,7 @@
LIST_ENTRY HandleTableListHead; LIST_ENTRY HandleTableListHead;
EX_PUSH_LOCK HandleTableListLock; EX_PUSH_LOCK HandleTableListLock;
#define SizeOfHandle(x) (sizeof(HANDLE) * (x)) #define SizeOfHandle(x) (sizeof(HANDLE) * (x))
#define INDEX_TO_HANDLE_VALUE(x) ((x) << HANDLE_TAG_BITS)
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
@ -67,12 +68,14 @@ ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
/* Get the mid level pointer array */ /* Get the mid level pointer array */
PointerArray = PointerArray[Handle.HighIndex]; PointerArray = PointerArray[Handle.HighIndex];
ASSERT(PointerArray != NULL);
/* Fall through */ /* Fall through */
case 1: case 1:
/* Get the handle array */ /* Get the handle array */
HandleArray = PointerArray[Handle.MidIndex]; HandleArray = PointerArray[Handle.MidIndex];
ASSERT(HandleArray != NULL);
/* Fall through */ /* Fall through */
case 0: case 0:
@ -255,8 +258,8 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
IN EXHANDLE Handle, IN EXHANDLE Handle,
IN PHANDLE_TABLE_ENTRY HandleTableEntry) IN PHANDLE_TABLE_ENTRY HandleTableEntry)
{ {
ULONG OldValue, NewValue, *Free; ULONG OldValue, *Free;
ULONG i; ULONG LockIndex;
PAGED_CODE(); PAGED_CODE();
/* Sanity checks */ /* Sanity checks */
@ -267,16 +270,16 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
InterlockedDecrement(&HandleTable->HandleCount); InterlockedDecrement(&HandleTable->HandleCount);
/* Mark the handle as free */ /* Mark the handle as free */
NewValue = (ULONG)Handle.Value & ~(SizeOfHandle(1) - 1); Handle.TagBits = 0;
/* Check if we're FIFO */ /* Check if we're FIFO */
if (!HandleTable->StrictFIFO) if (!HandleTable->StrictFIFO)
{ {
/* Select a lock index */ /* Select a lock index */
i = (NewValue >> 2) % 4; LockIndex = Handle.Index % 4;
/* Select which entry to use */ /* Select which entry to use */
Free = (HandleTable->HandleTableLock[i].Locked) ? Free = (HandleTable->HandleTableLock[LockIndex].Locked) ?
&HandleTable->FirstFree : &HandleTable->LastFree; &HandleTable->FirstFree : &HandleTable->LastFree;
} }
else else
@ -290,8 +293,8 @@ ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
{ {
/* Get the current value and write */ /* Get the current value and write */
OldValue = *Free; OldValue = *Free;
HandleTableEntry->NextFreeTableEntry = (ULONG)OldValue; HandleTableEntry->NextFreeTableEntry = OldValue;
if (InterlockedCompareExchange((PLONG) Free, NewValue, OldValue) == OldValue) if (InterlockedCompareExchange((PLONG)Free, Handle.AsULONG, OldValue) == OldValue)
{ {
/* Break out, we're done. Make sure the handle value makes sense */ /* Break out, we're done. Make sure the handle value makes sense */
ASSERT((OldValue & FREE_HANDLE_MASK) < ASSERT((OldValue & FREE_HANDLE_MASK) <
@ -354,7 +357,7 @@ ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL,
{ {
/* Set up the free data */ /* Set up the free data */
HandleEntry->Value = 0; HandleEntry->Value = 0;
HandleEntry->NextFreeTableEntry = (i + 1) * SizeOfHandle(1); HandleEntry->NextFreeTableEntry = INDEX_TO_HANDLE_VALUE(i + 1);
/* Move to the next entry */ /* Move to the next entry */
HandleEntry++; HandleEntry++;
@ -363,11 +366,11 @@ ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL,
/* Terminate the last entry */ /* Terminate the last entry */
HandleEntry->Value = 0; HandleEntry->Value = 0;
HandleEntry->NextFreeTableEntry = 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 */ /* 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 */ /* Setup the rest of the handle table data */
HandleTable->QuotaProcess = Process; HandleTable->QuotaProcess = Process;
@ -409,12 +412,12 @@ ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable,
{ {
/* Go to the next entry and the base entry */ /* Go to the next entry and the base entry */
HandleEntry++; HandleEntry++;
Base = HandleTable->NextHandleNeedingPool + SizeOfHandle(2); Base = HandleTable->NextHandleNeedingPool + INDEX_TO_HANDLE_VALUE(2);
/* Loop each entry */ /* Loop each entry */
for (i = Base; for (i = Base;
i < Base + SizeOfHandle(LOW_LEVEL_ENTRIES - 2); i < Base + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES - 2);
i += SizeOfHandle(1)) i += INDEX_TO_HANDLE_VALUE(1))
{ {
/* Free this entry and move on to the next one */ /* Free this entry and move on to the next one */
HandleEntry->NextFreeTableEntry = i; HandleEntry->NextFreeTableEntry = i;
@ -494,7 +497,7 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
/* Get if the next index can fit in the table */ /* Get if the next index can fit in the table */
i = HandleTable->NextHandleNeedingPool / i = HandleTable->NextHandleNeedingPool /
SizeOfHandle(LOW_LEVEL_ENTRIES); INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES);
if (i < MID_LEVEL_ENTRIES) if (i < MID_LEVEL_ENTRIES)
{ {
/* We need to allocate a new table */ /* We need to allocate a new table */
@ -539,7 +542,7 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
ThirdLevel = (PVOID)TableBase; ThirdLevel = (PVOID)TableBase;
/* Get the index and check if it can fit */ /* 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; if (i >= HIGH_LEVEL_ENTRIES) return FALSE;
/* Check if there's no mid-level table */ /* Check if there's no mid-level table */
@ -556,7 +559,7 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
else else
{ {
/* We have one, check at which index we should insert our entry */ /* We have one, check at which index we should insert our entry */
Index = (HandleTable->NextHandleNeedingPool / SizeOfHandle(1)) - Index = (HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(1)) -
i * MAX_MID_INDEX; i * MAX_MID_INDEX;
j = Index / LOW_LEVEL_ENTRIES; j = Index / LOW_LEVEL_ENTRIES;
@ -577,13 +580,13 @@ ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
/* Update the index of the next handle */ /* Update the index of the next handle */
Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool, Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool,
SizeOfHandle(LOW_LEVEL_ENTRIES)); INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
/* Check if need to initialize the table */ /* Check if need to initialize the table */
if (DoInit) if (DoInit)
{ {
/* Create a new index number */ /* Create a new index number */
Index += SizeOfHandle(1); Index += INDEX_TO_HANDLE_VALUE(1);
/* Start free index change loop */ /* Start free index change loop */
for (;;) for (;;)
@ -646,7 +649,7 @@ ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,
{ {
ULONG OldValue, NewValue, NewValue1; ULONG OldValue, NewValue, NewValue1;
PHANDLE_TABLE_ENTRY Entry; PHANDLE_TABLE_ENTRY Entry;
EXHANDLE Handle; EXHANDLE Handle, OldHandle;
BOOLEAN Result; BOOLEAN Result;
ULONG i; ULONG i;
@ -709,7 +712,8 @@ ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,
Entry = ExpLookupHandleTableEntry(HandleTable, Handle); Entry = ExpLookupHandleTableEntry(HandleTable, Handle);
/* Get an available lock and acquire it */ /* Get an available lock and acquire it */
i = ((OldValue & FREE_HANDLE_MASK) >> 2) % 4; OldHandle.Value = OldValue;
i = OldHandle.Index % 4;
KeEnterCriticalRegion(); KeEnterCriticalRegion();
ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]); ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]);
@ -1063,7 +1067,7 @@ ExDupHandleTable(IN PEPROCESS Process,
NewTable->FirstFree = 0; NewTable->FirstFree = 0;
/* Setup the first handle value */ /* 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 */ /* Enter a critical region and lookup the new entry */
KeEnterCriticalRegion(); KeEnterCriticalRegion();
@ -1125,13 +1129,13 @@ ExDupHandleTable(IN PEPROCESS Process,
} }
/* Increase the handle value and move to the next entry */ /* Increase the handle value and move to the next entry */
Handle.Value += SizeOfHandle(1); Handle.Value += INDEX_TO_HANDLE_VALUE(1);
NewEntry++; NewEntry++;
HandleTableEntry++; 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 */ /* 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 */ /* Acquire the table lock and insert this new table into the list */
@ -1198,7 +1202,7 @@ ExSweepHandleTable(IN PHANDLE_TABLE HandleTable,
PAGED_CODE(); PAGED_CODE();
/* Set the initial value and loop the entries */ /* Set the initial value and loop the entries */
Handle.Value = SizeOfHandle(1); Handle.Value = INDEX_TO_HANDLE_VALUE(1);
while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle))) while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
{ {
/* Loop each handle */ /* Loop each handle */
@ -1214,12 +1218,12 @@ ExSweepHandleTable(IN PHANDLE_TABLE HandleTable,
} }
/* Go to the next handle and entry */ /* Go to the next handle and entry */
Handle.Value += SizeOfHandle(1); Handle.Value += INDEX_TO_HANDLE_VALUE(1);
HandleTableEntry++; HandleTableEntry++;
} while (Handle.Value % SizeOfHandle(LOW_LEVEL_ENTRIES)); } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
/* Skip past the last entry */ /* 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 */ /* Go to the next entry */
Handle.Value += SizeOfHandle(1); Handle.Value += INDEX_TO_HANDLE_VALUE(1);
} }
/* Leave the critical region and return callback result */ /* Leave the critical region and return callback result */

View file

@ -68,25 +68,29 @@ VOID NTAPI ExpDebuggerWorker(IN PVOID Context);
#define HANDLE_LOW_BITS (PAGE_SHIFT - 3) #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
#define HANDLE_HIGH_BITS (PAGE_SHIFT - 2) #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
#endif #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 typedef union _EXHANDLE
{ {
struct struct
{ {
ULONG_PTR TagBits:2; ULONG_PTR TagBits: HANDLE_TAG_BITS;
ULONG_PTR Index:29; ULONG_PTR Index: HANDLE_INDEX_BITS;
ULONG_PTR KernelFlag : KERNEL_FLAG_BITS;
}; };
struct struct
{ {
ULONG_PTR TagBits2:2; ULONG_PTR TagBits2: HANDLE_TAG_BITS;
ULONG_PTR LowIndex: HANDLE_LOW_BITS; ULONG_PTR LowIndex: HANDLE_LOW_BITS;
ULONG_PTR MidIndex: HANDLE_HIGH_BITS; ULONG_PTR MidIndex: HANDLE_HIGH_BITS;
ULONG_PTR HighIndex: HANDLE_HIGH_BITS; ULONG_PTR HighIndex: HANDLE_HIGH_BITS;
ULONG_PTR KernelFlag:KERNEL_FLAG_BITS; ULONG_PTR KernelFlag2: KERNEL_FLAG_BITS;
}; };
HANDLE GenericHandleOverlay; HANDLE GenericHandleOverlay;
ULONG_PTR Value; ULONG_PTR Value;
ULONG AsULONG;
} EXHANDLE, *PEXHANDLE; } EXHANDLE, *PEXHANDLE;
typedef struct _ETIMER typedef struct _ETIMER