1521 lines
40 KiB
C
1521 lines
40 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1995 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
handle.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements a set of functions for supporting handles.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Steve Wood (stevewo) 25-Apr-1989
|
|||
|
David N. Cutler (davec) 17-May-1995 (rewrite)
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "exp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
//
|
|||
|
// Define global values for the default initial handle entry table size and
|
|||
|
// the default size to grow the handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
USHORT ExpDefaultHandleTableSize;
|
|||
|
USHORT ExpDefaultHandleTableGrowth;
|
|||
|
|
|||
|
//
|
|||
|
// Decline global structures that link all handle tables together.
|
|||
|
//
|
|||
|
|
|||
|
ERESOURCE HandleTableListLock;
|
|||
|
LIST_ENTRY HandleTableListHead;
|
|||
|
|
|||
|
//
|
|||
|
// Define forward referenced prototypes.
|
|||
|
//
|
|||
|
|
|||
|
PHANDLE_TABLE
|
|||
|
ExpAllocateHandleTable(
|
|||
|
IN PEPROCESS Process,
|
|||
|
IN ULONG CountToGrowBy
|
|||
|
);
|
|||
|
|
|||
|
PHANDLE_ENTRY
|
|||
|
ExpAllocateHandleTableEntries(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN PVOID OldTableEntries,
|
|||
|
IN ULONG OldCountEntries,
|
|||
|
IN ULONG NewCountEntries
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT, ExInitializeHandleTablePackage)
|
|||
|
#pragma alloc_text(PAGE, ExChangeHandle)
|
|||
|
#pragma alloc_text(PAGE, ExCreateHandle)
|
|||
|
#pragma alloc_text(PAGE, ExCreateHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExDestroyHandle)
|
|||
|
#pragma alloc_text(PAGE, ExDestroyHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExDupHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExEnumHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExMapHandleToPointer)
|
|||
|
#pragma alloc_text(PAGE, ExRemoveHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExSnapShotHandleTables)
|
|||
|
#pragma alloc_text(PAGE, ExpAllocateHandleTable)
|
|||
|
#pragma alloc_text(PAGE, ExpAllocateHandleTableEntries)
|
|||
|
#endif
|
|||
|
|
|||
|
VOID
|
|||
|
ExInitializeHandleTablePackage(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function initializes static data structures required to support
|
|||
|
handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
MM_SYSTEMSIZE SystemSize;
|
|||
|
|
|||
|
//
|
|||
|
// Get the configuration size of the host system and set the initial
|
|||
|
// and growth default sizes for handle table as appropriate.
|
|||
|
//
|
|||
|
// N.B. The initial sizes are set such that otimal use of pool block
|
|||
|
// storage can be obtained.
|
|||
|
//
|
|||
|
|
|||
|
SystemSize = MmQuerySystemSize();
|
|||
|
if (SystemSize == MmSmallSystem) {
|
|||
|
ExpDefaultHandleTableSize = 7;
|
|||
|
ExpDefaultHandleTableGrowth = 8;
|
|||
|
|
|||
|
} else {
|
|||
|
ExpDefaultHandleTableSize = 15;
|
|||
|
ExpDefaultHandleTableGrowth = 16;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the handle table synchronization resource and listhead.
|
|||
|
//
|
|||
|
|
|||
|
InitializeListHead(&HandleTableListHead);
|
|||
|
ExInitializeResource(&HandleTableListLock);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FASTCALL
|
|||
|
ExAcquireHandleTableExclusive(
|
|||
|
IN PHANDLE_TABLE HandleTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires the specified handle table for exclusive access.
|
|||
|
|
|||
|
N.B. This routine uses fast locking.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to the handle table that is acquired
|
|||
|
for exclusive access.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HANDLE_SYNCH Current;
|
|||
|
HANDLE_SYNCH NewState;
|
|||
|
|
|||
|
ASSERT(KeIsExecutingDpc() == FALSE);
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Capture the current state of handle table ownership and initialize
|
|||
|
// the proposed new state value.
|
|||
|
//
|
|||
|
// If the handle table is not owned, then attempt to grant exclusive
|
|||
|
// ownership. Otherwise, the handle table is owned either shared or
|
|||
|
// exclusive and the calling thread must wait for exclusive access.
|
|||
|
//
|
|||
|
|
|||
|
NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
|
|||
|
if (Current.u.OwnerCount == 0) {
|
|||
|
NewState.u.OwnerCount = (ULONG)PsGetCurrentThread();
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ASSERT((PETHREAD)(HandleTable->State.u.OwnerCount) != PsGetCurrentThread());
|
|||
|
|
|||
|
NewState.u.NumberOfExclusiveWaiters += 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&HandleTable->ExclusiveWaiters,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FASTCALL
|
|||
|
ExAcquireHandleTableShared(
|
|||
|
IN PHANDLE_TABLE HandleTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires the specified handle table for shared access.
|
|||
|
|
|||
|
N.B. This routines uses fast locking.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to the handle table that is acquired
|
|||
|
for shared access.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HANDLE_SYNCH Current;
|
|||
|
HANDLE_SYNCH NewState;
|
|||
|
|
|||
|
ASSERT(KeIsExecutingDpc() == FALSE);
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Capture the current state of handle table ownership and initialize
|
|||
|
// the proposed new state value.
|
|||
|
//
|
|||
|
// If the handle table is not owned or is owned shared, then attempt
|
|||
|
// to grant shared ownership. Otherwise, the handle table is owned
|
|||
|
// exclusive and the calling thread must wait for shared access.
|
|||
|
//
|
|||
|
// N.B. Shared access is granted if shared access is already granted
|
|||
|
// regardless of exclusive waiters.
|
|||
|
//
|
|||
|
|
|||
|
NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
|
|||
|
if ((Current.u.OwnerCount == 0) ||
|
|||
|
((Current.u.OwnerCount & 1) != 0)) {
|
|||
|
NewState.u.OwnerCount = (NewState.u.OwnerCount + 2) | 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
NewState.u.NumberOfSharedWaiters += 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&HandleTable->SharedWaiters,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FASTCALL
|
|||
|
ExReleaseHandleTableExclusive(
|
|||
|
IN PHANDLE_TABLE HandleTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine releases exclusive access to the specified handle table
|
|||
|
for the current thread.
|
|||
|
|
|||
|
N.B. This routine uses fast locking.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to the handle table to release.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HANDLE_SYNCH Current;
|
|||
|
HANDLE_SYNCH NewState;
|
|||
|
ULONG Number;
|
|||
|
|
|||
|
ASSERT(KeIsExecutingDpc() == FALSE);
|
|||
|
|
|||
|
ASSERT(((PETHREAD)HandleTable->State.u.OwnerCount == PsGetCurrentThread()) ||
|
|||
|
(HandleTable->State.u.OwnerCount == 2));
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Capture the current state of handle table ownership and initialize
|
|||
|
// the proposed new state value.
|
|||
|
//
|
|||
|
// If there are shared waiters, then attempt to grant shared access to
|
|||
|
// the handle table. Otherwise, it there are exclusive waiters, then
|
|||
|
// attempt to grant exclusive access to the handle table. Otherwise,
|
|||
|
// clear ownership of the handle table.
|
|||
|
//
|
|||
|
|
|||
|
NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
|
|||
|
if ((Number = Current.u.NumberOfSharedWaiters) != 0) {
|
|||
|
NewState.u.NumberOfSharedWaiters = 0;
|
|||
|
NewState.u.OwnerCount = (Number * 2) | 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
KeReleaseSemaphore(&HandleTable->SharedWaiters, 0, Number, FALSE);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else if (Current.u.NumberOfExclusiveWaiters != 0) {
|
|||
|
NewState.u.OwnerCount = 2;
|
|||
|
NewState.u.NumberOfExclusiveWaiters -= 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
KeSetEventBoostPriority(&HandleTable->ExclusiveWaiters,
|
|||
|
(PRKTHREAD *)&HandleTable->State.u.OwnerCount);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
NewState.u.OwnerCount = 0;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FASTCALL
|
|||
|
ExReleaseHandleTableShared(
|
|||
|
IN PHANDLE_TABLE HandleTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine releases shared access to the specified handle table for
|
|||
|
the current thread.
|
|||
|
|
|||
|
N.B. This routine uses fast locking.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to the handle table to release.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HANDLE_SYNCH Current;
|
|||
|
HANDLE_SYNCH NewState;
|
|||
|
ULONG Number;
|
|||
|
|
|||
|
ASSERT(KeIsExecutingDpc() == FALSE);
|
|||
|
|
|||
|
ASSERT((HandleTable->State.u.OwnerCount & 1) == 1);
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Capture the current state of handle table ownership and initialize
|
|||
|
// the proposed new state value.
|
|||
|
//
|
|||
|
// If there are exclusive waiters, then attempt to grant exclusive
|
|||
|
// access to the handle table. Otherwise, clear ownership of the
|
|||
|
// handle table (it is not possible to have shared waiters).
|
|||
|
//
|
|||
|
|
|||
|
NewState.Value = Current.Value = *((volatile ULONGLONG *)&HandleTable->State.Value);
|
|||
|
if (Current.u.OwnerCount != 3) {
|
|||
|
NewState.u.OwnerCount -= 2;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else if (Current.u.NumberOfExclusiveWaiters != 0) {
|
|||
|
NewState.u.OwnerCount = 2;
|
|||
|
NewState.u.NumberOfExclusiveWaiters -= 1;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
KeSetEventBoostPriority(&HandleTable->ExclusiveWaiters,
|
|||
|
(PRKTHREAD *)&HandleTable->State.u.OwnerCount);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
NewState.u.OwnerCount = 0;
|
|||
|
if (ExInterlockedCompareExchange64(&HandleTable->State.Value,
|
|||
|
&NewState.Value,
|
|||
|
&Current.Value,
|
|||
|
&HandleTable->SpinLock) == Current.Value) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ExChangeHandle(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PEX_CHANGE_HANDLE_ROUTINE ChangeRoutine,
|
|||
|
IN ULONG Parameter
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function provides the capability to change the contents of the
|
|||
|
handle entry corrsponding to the specified handle.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table.
|
|||
|
|
|||
|
Handle - Supplies the handle for the handle entry that is changed.
|
|||
|
|
|||
|
ChangeRoutine - Supplies a pointer to a function that is called to
|
|||
|
perform the change.
|
|||
|
|
|||
|
Parameter - Supplies an uninterpreted parameter that is passed to
|
|||
|
the change routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the operation was successfully performed, then a value of TRUE
|
|||
|
is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
BOOLEAN ReturnValue;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Lock the handle table exclusive and check if the handle is valid.
|
|||
|
//
|
|||
|
|
|||
|
ReturnValue = FALSE;
|
|||
|
TableIndex = HANDLE_TO_INDEX(Handle);
|
|||
|
ExLockHandleTableExclusive(HandleTable);
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
if (TableIndex < (ULONG)(TableBound - TableEntries)) {
|
|||
|
|
|||
|
//
|
|||
|
// Compute the address of the handle entry and call the change
|
|||
|
// handle function if the handle entry is not free.
|
|||
|
//
|
|||
|
|
|||
|
HandleEntry = &TableEntries[TableIndex];
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
ReturnValue = (*ChangeRoutine)(HandleEntry, Parameter);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
return ReturnValue;
|
|||
|
}
|
|||
|
|
|||
|
HANDLE
|
|||
|
ExCreateHandle(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN PHANDLE_ENTRY HandleEntry
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function create a handle entry in the specified handle table and
|
|||
|
returns a handle for the entry. If there is insufficient room in the
|
|||
|
handle table for a new entry, then the handle table is expanded if
|
|||
|
possible.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table
|
|||
|
|
|||
|
HandleEntry - Supplies a poiner to the handle entry for which a
|
|||
|
handle entry is created.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the handle entry is successfully created, then value of the created
|
|||
|
handle is returned as the function value. Otherwise, a value of NULL is
|
|||
|
returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PLIST_ENTRY FreeEntry;
|
|||
|
ULONG NewCountEntries;
|
|||
|
PHANDLE_ENTRY NewEntry;
|
|||
|
ULONG OldCountEntries;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
ASSERT(HandleEntry != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Lock the handle table exclusive and allocate a free handle entry.
|
|||
|
//
|
|||
|
|
|||
|
ExLockHandleTableExclusive(HandleTable);
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
if (IsListEmpty(&TableEntries->ListEntry)) {
|
|||
|
|
|||
|
//
|
|||
|
// There are no free entries in the handle entry table. Attempt
|
|||
|
// to grow the size of the handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
OldCountEntries = HandleTable->TableBound - TableEntries;
|
|||
|
NewCountEntries = OldCountEntries + HandleTable->CountToGrowBy;
|
|||
|
if (ExpAllocateHandleTableEntries(HandleTable,
|
|||
|
TableEntries,
|
|||
|
OldCountEntries,
|
|||
|
NewCountEntries) == NULL) {
|
|||
|
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
return NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the first entry from the free list, initialize the handle
|
|||
|
// entry, unlock the handle table, and return the handle value.
|
|||
|
//
|
|||
|
// N.B. The LIFO/FIFO discipline for handle table entires is maintained
|
|||
|
// at the point handles are destroyed.
|
|||
|
//
|
|||
|
|
|||
|
FreeEntry = TableEntries->ListEntry.Flink;
|
|||
|
RemoveEntryList(FreeEntry);
|
|||
|
NewEntry = CONTAINING_RECORD(FreeEntry, HANDLE_ENTRY, ListEntry);
|
|||
|
HandleTable->HandleCount += 1;
|
|||
|
NewEntry->Object = HandleEntry->Object;
|
|||
|
NewEntry->Attributes = HandleEntry->Attributes;
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
TableIndex = NewEntry - TableEntries;
|
|||
|
return INDEX_TO_HANDLE(TableIndex);
|
|||
|
}
|
|||
|
|
|||
|
PHANDLE_TABLE
|
|||
|
ExCreateHandleTable(
|
|||
|
IN PEPROCESS Process OPTIONAL,
|
|||
|
IN ULONG CountEntries,
|
|||
|
IN ULONG CountToGrowBy
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function creates a handle table and allocates the specified count
|
|||
|
of initial handle entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies an optional pointer to the process against which quota
|
|||
|
will be charged.
|
|||
|
|
|||
|
CountEntries - Supplies the initial number of handle entries to allocate.
|
|||
|
|
|||
|
CountToGrowBy - Supplies the number of handle entries to grow the handle
|
|||
|
entry table by when it becomes full.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If a handle table is successfully created, then the address of the
|
|||
|
handle table is returned as the function value. Otherwize, a value
|
|||
|
NULL is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_TABLE HandleTable;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// If the number of initial handle entries or the number to grow by
|
|||
|
// are not specified, then use the system default value.
|
|||
|
//
|
|||
|
|
|||
|
if ((CountEntries <= 1) || (CountEntries > MAXUSHORT)) {
|
|||
|
CountEntries = ExpDefaultHandleTableSize;
|
|||
|
}
|
|||
|
|
|||
|
if ((CountToGrowBy <= 1) || (CountToGrowBy > MAXUSHORT)) {
|
|||
|
CountToGrowBy = ExpDefaultHandleTableGrowth;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and initialize a handle table descriptor.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable = ExpAllocateHandleTable(Process, CountToGrowBy);
|
|||
|
|
|||
|
//
|
|||
|
// If the handle table descriptor was successfully allocated, then
|
|||
|
// allocate the initial handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
if (HandleTable != NULL) {
|
|||
|
if (ExpAllocateHandleTableEntries(HandleTable,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
CountEntries) == NULL) {
|
|||
|
|
|||
|
ExDestroyHandleTable(HandleTable, NULL);
|
|||
|
HandleTable = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return HandleTable;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ExDestroyHandle(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN HANDLE Handle,
|
|||
|
IN BOOLEAN TableLocked
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function removes a handle from a handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table
|
|||
|
|
|||
|
Handle - Supplies the handle value of the entry to remove.
|
|||
|
|
|||
|
TableLocked - Supplies a boolean value that determines whether the
|
|||
|
handle table is already locked.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified handle is successfully removed, then a value of
|
|||
|
TRUE is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
BOOLEAN ResultValue;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// If the handle table is not already locked, then lock the handle
|
|||
|
// table exclussive.
|
|||
|
//
|
|||
|
|
|||
|
ResultValue = FALSE;
|
|||
|
TableIndex = HANDLE_TO_INDEX(Handle);
|
|||
|
if (TableLocked == FALSE) {
|
|||
|
ExLockHandleTableExclusive(HandleTable);
|
|||
|
}
|
|||
|
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
if (TableIndex < (ULONG)(TableBound - TableEntries)) {
|
|||
|
|
|||
|
//
|
|||
|
// Compute the address of the handle entry and check if the handle
|
|||
|
// is is use.
|
|||
|
//
|
|||
|
|
|||
|
HandleEntry = &TableEntries[TableIndex];
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
|
|||
|
//
|
|||
|
// Insert the handle entry in the free list according to the
|
|||
|
// discipline associated with the handle table and decrement
|
|||
|
// the number of handles.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable->HandleCount -= 1;
|
|||
|
if (HandleTable->LifoOrder != FALSE) {
|
|||
|
InsertHeadList(&TableEntries->ListEntry, &HandleEntry->ListEntry);
|
|||
|
|
|||
|
} else {
|
|||
|
InsertTailList(&TableEntries->ListEntry, &HandleEntry->ListEntry);
|
|||
|
}
|
|||
|
|
|||
|
ResultValue = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unlock the handle table if is was locked.
|
|||
|
//
|
|||
|
|
|||
|
if (TableLocked == FALSE) {
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
}
|
|||
|
|
|||
|
return ResultValue;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ExRemoveHandleTable(
|
|||
|
IN PHANDLE_TABLE HandleTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function removes the specified handle table from the list of
|
|||
|
handle tables. Used by PS and ATOM packages to make sure their
|
|||
|
handle tables are not in the list enumerated by the ExSnapShotHandleTables
|
|||
|
routine and the !handle debugger extension.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Remove the handle table from the handle table list.
|
|||
|
//
|
|||
|
|
|||
|
KeEnterCriticalRegion();
|
|||
|
ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
|
|||
|
if (!IsListEmpty(&HandleTable->ListEntry)) {
|
|||
|
RemoveEntryList(&HandleTable->ListEntry);
|
|||
|
InitializeListHead(&HandleTable->ListEntry);
|
|||
|
}
|
|||
|
ExReleaseResource(&HandleTableListLock);
|
|||
|
KeLeaveCriticalRegion();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ExDestroyHandleTable(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN EX_DESTROY_HANDLE_ROUTINE DestroyHandleProcedure OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function destroys the specified handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table
|
|||
|
|
|||
|
DestroyHandleProcedure - Supplies a pointer to a function to call for
|
|||
|
each valid handle entry in the handle table.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG CountEntries;
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
PEPROCESS Process;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Remove the handle table from the handle table list.
|
|||
|
//
|
|||
|
|
|||
|
ExRemoveHandleTable(HandleTable);
|
|||
|
|
|||
|
//
|
|||
|
// If a handle entry table has been allocated, then scan all of
|
|||
|
// handle entries, call the destroy handle function, if specfied,
|
|||
|
// free the allocated pool, and return pool quota as appropriate.
|
|||
|
//
|
|||
|
|
|||
|
Process = HandleTable->QuotaProcess;
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
if (TableEntries != NULL) {
|
|||
|
if (ARGUMENT_PRESENT(DestroyHandleProcedure)) {
|
|||
|
HandleEntry = &TableEntries[1];
|
|||
|
while (HandleEntry < TableBound) {
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
TableIndex = HandleEntry - TableEntries;
|
|||
|
(*DestroyHandleProcedure)(INDEX_TO_HANDLE(TableIndex),
|
|||
|
HandleEntry);
|
|||
|
}
|
|||
|
|
|||
|
HandleEntry += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(TableEntries);
|
|||
|
if (Process != NULL) {
|
|||
|
CountEntries = TableBound - TableEntries;
|
|||
|
PsReturnPoolQuota(Process,
|
|||
|
PagedPool,
|
|||
|
CountEntries * sizeof(HANDLE_ENTRY));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the allocated pool and return pool quota as appropriate.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(HandleTable);
|
|||
|
if (Process != NULL) {
|
|||
|
PsReturnPoolQuota(Process,
|
|||
|
NonPagedPool,
|
|||
|
sizeof(HANDLE_TABLE));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PHANDLE_TABLE
|
|||
|
ExDupHandleTable(
|
|||
|
IN PEPROCESS Process OPTIONAL,
|
|||
|
IN PHANDLE_TABLE OldHandleTable,
|
|||
|
IN EX_DUPLICATE_HANDLE_ROUTINE DupHandleProcedure OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function creates a duplicate copy of the specified handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies an optional to the process to charge quota to.
|
|||
|
|
|||
|
OldHandleTable - Supplies a pointer to a handle table.
|
|||
|
|
|||
|
DupHandleProcedure - Supplies an optional pointer to a function to call
|
|||
|
for each valid handle in the duplicated handle table.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified handle table is successfully duplicated, then the
|
|||
|
address of the new handle table is returned as the function value.
|
|||
|
Otherwize, a value NULL is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PLIST_ENTRY FreeHead;
|
|||
|
PHANDLE_TABLE NewHandleTable;
|
|||
|
PHANDLE_ENTRY NewHandleEntry;
|
|||
|
PHANDLE_ENTRY NewTableEntries;
|
|||
|
PHANDLE_ENTRY OldHandleEntry;
|
|||
|
ULONG OldCountEntries;
|
|||
|
PHANDLE_ENTRY OldTableBound;
|
|||
|
PHANDLE_ENTRY OldTableEntries;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(OldHandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Lock the old handle table exclusive and allocate and initialize
|
|||
|
// a handle table descriptor.
|
|||
|
//
|
|||
|
|
|||
|
ExLockHandleTableExclusive(OldHandleTable);
|
|||
|
NewHandleTable = ExpAllocateHandleTable(Process,
|
|||
|
OldHandleTable->CountToGrowBy);
|
|||
|
|
|||
|
//
|
|||
|
// If the new handle table descriptor was successfully allocated, then
|
|||
|
// the allocate the handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
if (NewHandleTable != NULL) {
|
|||
|
OldTableBound = OldHandleTable->TableBound;
|
|||
|
OldTableEntries = OldHandleTable->TableEntries;
|
|||
|
OldCountEntries = OldTableBound - OldTableEntries;
|
|||
|
if (ExpAllocateHandleTableEntries(NewHandleTable,
|
|||
|
OldTableEntries,
|
|||
|
0,
|
|||
|
OldCountEntries) == NULL) {
|
|||
|
|
|||
|
ExDestroyHandleTable(NewHandleTable, NULL);
|
|||
|
NewHandleTable = NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Scan through the old handle table and either duplicate the
|
|||
|
// associated entry or insert it in the free list.
|
|||
|
//
|
|||
|
|
|||
|
NewTableEntries = NewHandleTable->TableEntries;
|
|||
|
FreeHead = &NewTableEntries->ListEntry;
|
|||
|
OldHandleEntry = &OldTableEntries[1];
|
|||
|
NewHandleEntry = &NewTableEntries[1];
|
|||
|
while (OldHandleEntry < OldTableBound) {
|
|||
|
if (ExIsEntryFree(OldTableEntries, OldTableBound, OldHandleEntry)) {
|
|||
|
InsertTailList(FreeHead, &NewHandleEntry->ListEntry);
|
|||
|
|
|||
|
} else {
|
|||
|
NewHandleEntry->Object = OldHandleEntry->Object;
|
|||
|
NewHandleEntry->Attributes = OldHandleEntry->Attributes;
|
|||
|
if (ARGUMENT_PRESENT(DupHandleProcedure)) {
|
|||
|
if ((*DupHandleProcedure)(Process, NewHandleEntry)) {
|
|||
|
NewHandleTable->HandleCount += 1;
|
|||
|
|
|||
|
} else {
|
|||
|
InsertTailList(FreeHead, &NewHandleEntry->ListEntry);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
NewHandleTable->HandleCount += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NewHandleEntry += 1;
|
|||
|
OldHandleEntry += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExUnlockHandleTableExclusive(OldHandleTable);
|
|||
|
return NewHandleTable;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ExEnumHandleTable(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
|
|||
|
IN PVOID EnumParameter,
|
|||
|
OUT PHANDLE Handle OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function enumerates all the valid handles in a handle table.
|
|||
|
For each valid handle in the handle table, the specified eumeration
|
|||
|
function is called. If the enumeration function returns TRUE, then
|
|||
|
the enumeration is stopped, the current handle is returned to the
|
|||
|
caller via the optional Handle parameter, and this function returns
|
|||
|
TRUE to indicated that the enumeration stopped at a specific handle.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table.
|
|||
|
|
|||
|
EnumHandleProcedure - Supplies a pointer to a fucntion to call for
|
|||
|
each valid handle in the enumerated handle table.
|
|||
|
|
|||
|
EnumParameter - Supplies an uninterpreted 32-bit value that is passed
|
|||
|
to the EnumHandleProcedure each time it is called.
|
|||
|
|
|||
|
Handle - Supplies an optional pointer a variable that receives the
|
|||
|
Handle value that the enumeration stopped at. Contents of the
|
|||
|
variable only valid if this function returns TRUE.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the enumeration stopped at a specific handle, then a value of TRUE
|
|||
|
is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
BOOLEAN ResultValue;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Lock the handle table exclusive and enumerate the handle entries.
|
|||
|
//
|
|||
|
|
|||
|
ResultValue = FALSE;
|
|||
|
ExLockHandleTableShared(HandleTable);
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
HandleEntry = &TableEntries[1];
|
|||
|
while (HandleEntry < TableBound) {
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
TableIndex = HandleEntry - TableEntries;
|
|||
|
if ((*EnumHandleProcedure)(HandleEntry,
|
|||
|
INDEX_TO_HANDLE(TableIndex),
|
|||
|
EnumParameter)) {
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Handle)) {
|
|||
|
*Handle = INDEX_TO_HANDLE(TableIndex);
|
|||
|
}
|
|||
|
|
|||
|
ResultValue = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
HandleEntry += 1;
|
|||
|
}
|
|||
|
|
|||
|
ExUnlockHandleTableShared(HandleTable);
|
|||
|
return ResultValue;
|
|||
|
}
|
|||
|
|
|||
|
PHANDLE_ENTRY
|
|||
|
ExMapHandleToPointer(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN HANDLE Handle,
|
|||
|
IN BOOLEAN Shared
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function maps a handle to a pointer to a handle entry. If the
|
|||
|
map operation is successful, then this function returns with the
|
|||
|
handle table locked.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table.
|
|||
|
|
|||
|
Handle - Supplies the handle to be mapped to a handle entry.
|
|||
|
|
|||
|
Shared - Supplies a boolean value that determines whether the handle
|
|||
|
table is locked for shared (TRUE) or exclusive (FALSE) access.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the handle was successfully mapped to a pointer to a handle entry,
|
|||
|
then the address of the handle entry is returned as the function value
|
|||
|
with the handle table locked. Otherwise, a value of NULL is returned with
|
|||
|
the handle table unlocked.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(HandleTable != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Lock the handle table exclusive or shared and check if the handle
|
|||
|
// if valid.
|
|||
|
//
|
|||
|
|
|||
|
TableIndex = HANDLE_TO_INDEX(Handle);
|
|||
|
if (Shared != FALSE) {
|
|||
|
ExLockHandleTableShared(HandleTable);
|
|||
|
|
|||
|
} else {
|
|||
|
ExLockHandleTableExclusive(HandleTable);
|
|||
|
}
|
|||
|
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
if (TableIndex < (ULONG)(TableBound - TableEntries)) {
|
|||
|
HandleEntry = &TableEntries[TableIndex];
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
return HandleEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Shared != FALSE) {
|
|||
|
ExUnlockHandleTableShared(HandleTable);
|
|||
|
|
|||
|
} else {
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ExSnapShotHandleTables(
|
|||
|
IN PEX_SNAPSHOT_HANDLE_ENTRY SnapShotHandleEntry,
|
|||
|
IN OUT PSYSTEM_HANDLE_INFORMATION HandleInformation,
|
|||
|
IN ULONG Length,
|
|||
|
IN OUT PULONG RequiredLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sets the handle allocation algorithm for the specified
|
|||
|
handle table.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
...
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY HandleEntry;
|
|||
|
PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntryInfo;
|
|||
|
PHANDLE_TABLE HandleTable;
|
|||
|
PLIST_ENTRY NextEntry;
|
|||
|
NTSTATUS Status;
|
|||
|
PHANDLE_ENTRY TableBound;
|
|||
|
PHANDLE_ENTRY TableEntries;
|
|||
|
ULONG TableIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Lock the handle table list exclusive and traverse the list of
|
|||
|
// handle tables.
|
|||
|
//
|
|||
|
|
|||
|
KeEnterCriticalRegion();
|
|||
|
ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
|
|||
|
try {
|
|||
|
HandleEntryInfo = &HandleInformation->Handles[0];
|
|||
|
NextEntry = HandleTableListHead.Flink;
|
|||
|
while (NextEntry != &HandleTableListHead) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the next handle table, lock the handle
|
|||
|
// table exclusive, and scan the list of handle entries.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable = CONTAINING_RECORD(NextEntry, HANDLE_TABLE, ListEntry);
|
|||
|
ExLockHandleTableExclusive(HandleTable);
|
|||
|
TableBound = HandleTable->TableBound;
|
|||
|
TableEntries = HandleTable->TableEntries;
|
|||
|
HandleEntry = &TableEntries[1];
|
|||
|
try {
|
|||
|
for (HandleEntry = &TableEntries[1];
|
|||
|
HandleEntry < TableBound;
|
|||
|
HandleEntry++) {
|
|||
|
if (ExIsEntryUsed(TableEntries, TableBound, HandleEntry)) {
|
|||
|
HandleInformation->NumberOfHandles += 1;
|
|||
|
TableIndex = HandleEntry - TableEntries;
|
|||
|
Status = (*SnapShotHandleEntry)(&HandleEntryInfo,
|
|||
|
HandleTable->UniqueProcessId,
|
|||
|
HandleEntry,
|
|||
|
INDEX_TO_HANDLE(TableIndex),
|
|||
|
Length,
|
|||
|
RequiredLength);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} finally {
|
|||
|
ExUnlockHandleTableExclusive(HandleTable);
|
|||
|
}
|
|||
|
|
|||
|
NextEntry = NextEntry->Flink;
|
|||
|
}
|
|||
|
|
|||
|
} finally {
|
|||
|
ExReleaseResource(&HandleTableListLock);
|
|||
|
KeLeaveCriticalRegion();
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
PHANDLE_TABLE
|
|||
|
ExpAllocateHandleTable(
|
|||
|
IN PEPROCESS Process OPTIONAL,
|
|||
|
IN ULONG CountToGrowBy
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates and initializes a new handle table descriptor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies an optional pointer to a process to charge quota
|
|||
|
against.
|
|||
|
|
|||
|
CountToGrowBy - Supplies the number of handle entries to grow the
|
|||
|
handle table by.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If a handle is successfully allocated, then the address of the handle
|
|||
|
table is returned as the function value. Otherwise, NULL is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_TABLE HandleTable;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Allocate handle table from nonpaged pool.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable =
|
|||
|
(PHANDLE_TABLE)ExAllocatePoolWithTag(NonPagedPool,
|
|||
|
sizeof(HANDLE_TABLE),
|
|||
|
'btbO');
|
|||
|
|
|||
|
//
|
|||
|
// If the allocation is successful, then attempt to charge quota as
|
|||
|
// appropriate and initialize the handle tabel descriptor.
|
|||
|
//
|
|||
|
|
|||
|
if (HandleTable != NULL) {
|
|||
|
if (ARGUMENT_PRESENT(Process)) {
|
|||
|
try {
|
|||
|
PsChargePoolQuota(Process,
|
|||
|
NonPagedPool,
|
|||
|
sizeof(HANDLE_TABLE));
|
|||
|
|
|||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
ExFreePool(HandleTable);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the handle table access synchronization information.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable->State.u.OwnerCount = 0;
|
|||
|
HandleTable->State.u.NumberOfSharedWaiters = 0;
|
|||
|
HandleTable->State.u.NumberOfExclusiveWaiters = 0;
|
|||
|
KeInitializeSpinLock(&HandleTable->SpinLock);
|
|||
|
KeInitializeSemaphore(&HandleTable->SharedWaiters, 0, MAXLONG);
|
|||
|
KeInitializeEvent(&HandleTable->ExclusiveWaiters,
|
|||
|
SynchronizationEvent,
|
|||
|
FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the handle table descriptor.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable->LifoOrder = FALSE;
|
|||
|
HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId;
|
|||
|
HandleTable->TableEntries = NULL;
|
|||
|
HandleTable->TableBound = NULL;
|
|||
|
HandleTable->QuotaProcess = Process;
|
|||
|
HandleTable->HandleCount = 0;
|
|||
|
HandleTable->CountToGrowBy = (USHORT)CountToGrowBy;
|
|||
|
|
|||
|
//
|
|||
|
// Insert the handle table in the handle table list.
|
|||
|
//
|
|||
|
|
|||
|
KeEnterCriticalRegion();
|
|||
|
ExAcquireResourceExclusive(&HandleTableListLock, TRUE);
|
|||
|
InsertTailList(&HandleTableListHead, &HandleTable->ListEntry);
|
|||
|
ExReleaseResource(&HandleTableListLock);
|
|||
|
KeLeaveCriticalRegion();
|
|||
|
}
|
|||
|
|
|||
|
return HandleTable;
|
|||
|
}
|
|||
|
|
|||
|
PHANDLE_ENTRY
|
|||
|
ExpAllocateHandleTableEntries(
|
|||
|
IN PHANDLE_TABLE HandleTable,
|
|||
|
IN PHANDLE_ENTRY OldTableEntries,
|
|||
|
IN ULONG OldCountEntries,
|
|||
|
IN ULONG NewCountEntries
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates and initializes a new set of free handle
|
|||
|
table entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
HandleTable - Supplies a pointer to a handle table descriptor.
|
|||
|
|
|||
|
OldTableEntries - Supplies a pointer to the old set of handle table
|
|||
|
entries.
|
|||
|
|
|||
|
OldCountEntries - Supplies the previous count of table entries.
|
|||
|
|
|||
|
NewCountEntries - Supplies the desired count of table entries.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If a new set of handle entries is successfully allocated, then the
|
|||
|
address of the handle entries is returned as the function value.
|
|||
|
Otherwise, NULL is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PHANDLE_ENTRY FreeEntry;
|
|||
|
PLIST_ENTRY FreeHead;
|
|||
|
ULONG NewCountBytes;
|
|||
|
PHANDLE_ENTRY NewTableBound;
|
|||
|
PHANDLE_ENTRY NewTableEntries;
|
|||
|
LONG OldCountBytes;
|
|||
|
PEPROCESS Process;
|
|||
|
BOOLEAN Status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(NewCountEntries > OldCountEntries);
|
|||
|
|
|||
|
//
|
|||
|
// Compute the old and new sizes for the handle entry table and
|
|||
|
// allocate a new handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
OldCountBytes = OldCountEntries * sizeof(HANDLE_ENTRY);
|
|||
|
NewCountBytes = NewCountEntries * sizeof(HANDLE_ENTRY);
|
|||
|
NewTableEntries = (PHANDLE_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
|||
|
NewCountBytes,
|
|||
|
'btbO');
|
|||
|
|
|||
|
//
|
|||
|
// If the allocation is successful, then attempt to charge quota as
|
|||
|
// appropriate and initialize the free list of handle entries.
|
|||
|
//
|
|||
|
|
|||
|
if (NewTableEntries != NULL) {
|
|||
|
Process = HandleTable->QuotaProcess;
|
|||
|
if (Process != NULL) {
|
|||
|
try {
|
|||
|
PsChargePoolQuota(Process,
|
|||
|
PagedPool,
|
|||
|
NewCountBytes - OldCountBytes);
|
|||
|
|
|||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
ExFreePool(NewTableEntries);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the free listhead.
|
|||
|
//
|
|||
|
|
|||
|
FreeHead = &NewTableEntries->ListEntry;
|
|||
|
InitializeListHead(FreeHead);
|
|||
|
|
|||
|
//
|
|||
|
// If a new handle table is being created or an existing handle
|
|||
|
// table is being extended, then initialize the free entry list
|
|||
|
// allocated in the extension.
|
|||
|
//
|
|||
|
|
|||
|
NewTableBound = &NewTableEntries[NewCountEntries];
|
|||
|
if ((OldTableEntries == NULL) || (OldCountEntries != 0)) {
|
|||
|
if (OldCountEntries == 0) {
|
|||
|
FreeEntry = &NewTableEntries[1];
|
|||
|
|
|||
|
} else {
|
|||
|
FreeEntry = &NewTableEntries[OldCountEntries];
|
|||
|
}
|
|||
|
|
|||
|
do {
|
|||
|
InsertTailList(FreeHead, &FreeEntry->ListEntry);
|
|||
|
FreeEntry += 1;
|
|||
|
} while (FreeEntry < NewTableBound);
|
|||
|
|
|||
|
//
|
|||
|
// If there is an old handle entry table, then move the old
|
|||
|
// handle entires to the new handle entry table and free the
|
|||
|
// old handle entry table.
|
|||
|
//
|
|||
|
|
|||
|
if (OldTableEntries != NULL) {
|
|||
|
RtlMoveMemory(&NewTableEntries[1],
|
|||
|
&OldTableEntries[1],
|
|||
|
OldCountBytes - sizeof(HANDLE_ENTRY));
|
|||
|
|
|||
|
ExFreePool(OldTableEntries);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the new count of table entries, the new table bound, and
|
|||
|
// the address of the new table entries.
|
|||
|
//
|
|||
|
|
|||
|
HandleTable->TableBound = NewTableBound;
|
|||
|
HandleTable->TableEntries = NewTableEntries;
|
|||
|
}
|
|||
|
|
|||
|
return NewTableEntries;
|
|||
|
}
|