Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1780 lines
50 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
obhandle.c
Abstract:
Object handle routines
Author:
Steve Wood (stevewo) 31-Mar-1989
Revision History:
--*/
#include "obp.h"
//
// Define logical sum of all generic accesses.
//
#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
//
// Define local prototypes
//
NTSTATUS
ObpIncrementHandleDataBase(
IN POBJECT_HEADER ObjectHeader,
IN PEPROCESS Process,
OUT PULONG NewProcessHandleCount
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,NtDuplicateObject)
#pragma alloc_text(PAGE,ObpInsertHandleCount)
#pragma alloc_text(PAGE,ObpIncrementHandleCount)
#pragma alloc_text(PAGE,ObpIncrementUnnamedHandleCount)
#pragma alloc_text(PAGE,ObpDecrementHandleCount)
#pragma alloc_text(PAGE,ObpCreateHandle)
#pragma alloc_text(PAGE,ObpCreateUnnamedHandle)
#pragma alloc_text(PAGE,ObpIncrementHandleDataBase)
#endif
extern KMUTANT ObpInitKillMutant;
#ifdef MPSAFE_HANDLE_COUNT_CHECK
VOID
FASTCALL
ObpIncrPointerCount(
IN POBJECT_HEADER ObjectHeader
)
{
KIRQL OldIrql;
ExAcquireFastLock( &ObpLock, &OldIrql );
ObjectHeader->PointerCount += 1;
ExReleaseFastLock( &ObpLock, OldIrql );
}
VOID
FASTCALL
ObpDecrPointerCount(
IN POBJECT_HEADER ObjectHeader
)
{
KIRQL OldIrql;
ExAcquireFastLock( &ObpLock, &OldIrql );
ObjectHeader->PointerCount -= 1;
ExReleaseFastLock( &ObpLock, OldIrql );
}
BOOLEAN
FASTCALL
ObpDecrPointerCountWithResult(
IN POBJECT_HEADER ObjectHeader
)
{
KIRQL OldIrql;
LONG Result;
ExAcquireFastLock( &ObpLock, &OldIrql );
if (ObjectHeader->PointerCount <= ObjectHeader->HandleCount) {
DbgPrint( "OB: About to over-dereference object %x (ObjectHeader at %x)\n",
ObjectHeader->Object, ObjectHeader
);
DbgBreakPoint();
}
ObjectHeader->PointerCount -= 1;
Result = ObjectHeader->PointerCount;
ExReleaseFastLock( &ObpLock, OldIrql );
return Result == 0;
}
VOID
FASTCALL
ObpIncrHandleCount(
IN POBJECT_HEADER ObjectHeader
)
{
KIRQL OldIrql;
ExAcquireFastLock( &ObpLock, &OldIrql );
ObjectHeader->HandleCount += 1;
ExReleaseFastLock( &ObpLock, OldIrql );
}
BOOLEAN
FASTCALL
ObpDecrHandleCount(
IN POBJECT_HEADER ObjectHeader
)
{
KIRQL OldIrql;
LONG Old;
ExAcquireFastLock( &ObpLock, &OldIrql );
Old = ObjectHeader->HandleCount;
ObjectHeader->HandleCount -= 1;
ExReleaseFastLock( &ObpLock, OldIrql );
return Old == 1;
}
#endif // MPSAFE_HANDLE_COUNT_CHECK
POBJECT_HANDLE_COUNT_ENTRY
ObpInsertHandleCount(
POBJECT_HEADER ObjectHeader
)
{
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_DATABASE OldHandleCountDataBase;
POBJECT_HANDLE_COUNT_DATABASE NewHandleCountDataBase;
POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
ULONG CountEntries;
ULONG OldSize;
ULONG NewSize;
OBJECT_HANDLE_COUNT_DATABASE SingleEntryDataBase;
PAGED_CODE();
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
if (HandleInfo == NULL) {
return NULL;
}
if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
SingleEntryDataBase.CountEntries = 1;
SingleEntryDataBase.HandleCountEntries[0] = HandleInfo->SingleEntry;
OldHandleCountDataBase = &SingleEntryDataBase;
OldSize = sizeof( SingleEntryDataBase );
CountEntries = 2;
NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY ));
} else {
OldHandleCountDataBase = HandleInfo->HandleCountDataBase;
CountEntries = OldHandleCountDataBase->CountEntries;
OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
CountEntries += 4;
NewSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
((CountEntries - 1) * sizeof( OBJECT_HANDLE_COUNT_ENTRY));
}
NewHandleCountDataBase = ExAllocatePoolWithTag(PagedPool, NewSize,'dHbO');
if (NewHandleCountDataBase == NULL) {
return NULL;
}
RtlMoveMemory(NewHandleCountDataBase, OldHandleCountDataBase, OldSize);
if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
ObjectHeader->Flags &= ~OB_FLAG_SINGLE_HANDLE_ENTRY;
} else {
ExFreePool( OldHandleCountDataBase );
}
FreeHandleCountEntry =
(POBJECT_HANDLE_COUNT_ENTRY)((PCHAR)NewHandleCountDataBase + OldSize);
RtlZeroMemory(FreeHandleCountEntry, NewSize - OldSize);
NewHandleCountDataBase->CountEntries = CountEntries;
HandleInfo->HandleCountDataBase = NewHandleCountDataBase;
return FreeHandleCountEntry;
}
NTSTATUS
ObpIncrementHandleDataBase(
IN POBJECT_HEADER ObjectHeader,
IN PEPROCESS Process,
OUT PULONG NewProcessHandleCount
)
/*++
Routine Description:
This function increments the handle count database associated with the
specified object for a specified process.
Arguments:
ObjectHeader - Supplies a pointer to the object.
Process - Supplies a pointer to the process whose handle count is to be
updated.
NewProcessHandleCount - Supplies a pointer to a variable that receives
the new handle count for the process.
Return Value:
NTSTATUS
--*/
{
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
POBJECT_HANDLE_COUNT_ENTRY FreeHandleCountEntry;
ULONG CountEntries;
ULONG ProcessHandleCount;
PAGED_CODE();
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
if (HandleInfo->SingleEntry.HandleCount == 0) {
*NewProcessHandleCount = 1;
HandleInfo->SingleEntry.HandleCount = 1;
HandleInfo->SingleEntry.Process = Process;
return STATUS_SUCCESS;
} else if (HandleInfo->SingleEntry.Process == Process) {
*NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
return STATUS_SUCCESS;
} else {
FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
if (FreeHandleCountEntry == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
FreeHandleCountEntry->Process = Process;
FreeHandleCountEntry->HandleCount = 1;
*NewProcessHandleCount = 1;
return STATUS_SUCCESS;
}
}
HandleCountDataBase = HandleInfo->HandleCountDataBase;
FreeHandleCountEntry = NULL;
if (HandleCountDataBase != NULL) {
CountEntries = HandleCountDataBase->CountEntries;
HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
while (CountEntries) {
if (HandleCountEntry->Process == Process) {
*NewProcessHandleCount = ++HandleCountEntry->HandleCount;
return STATUS_SUCCESS;
} else if (HandleCountEntry->HandleCount == 0) {
FreeHandleCountEntry = HandleCountEntry;
}
++HandleCountEntry;
--CountEntries;
}
if (FreeHandleCountEntry == NULL) {
FreeHandleCountEntry = ObpInsertHandleCount( ObjectHeader );
if (FreeHandleCountEntry == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
}
FreeHandleCountEntry->Process = Process;
FreeHandleCountEntry->HandleCount = 1;
*NewProcessHandleCount = 1;
}
return STATUS_SUCCESS;
}
NTSTATUS
ObpIncrementHandleCount(
OB_OPEN_REASON OpenReason,
PEPROCESS Process,
PVOID Object,
POBJECT_TYPE ObjectType,
PACCESS_STATE AccessState OPTIONAL,
KPROCESSOR_MODE AccessMode,
ULONG Attributes
)
/*++
Routine Description:
Increments the count of number of handles to the given object.
If the object is being opened or created, access validation and
auditing will be performed as appropriate.
Arguments:
OpenReason - Supplies the reason the handle count is being incremented.
Process - Pointer to the process in which the new handle will reside.
ObjectHeader - Supplies the header to the object.
ObjectType - Supplies the type of the object.
AccessState - Optional parameter supplying the current accumulated
security information describing the attempt to access the object.
Attributes -
Return Value:
--*/
{
NTSTATUS Status;
ULONG ProcessHandleCount;
BOOLEAN ExclusiveHandle;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
POBJECT_HEADER ObjectHeader;
BOOLEAN HasPrivilege = FALSE;
PRIVILEGE_SET Privileges;
BOOLEAN NewObject;
PAGED_CODE();
ObpValidateIrql( "ObpIncrementHandleCount" );
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
if (!NT_SUCCESS( Status )) {
return Status;
}
ObpEnterObjectTypeMutex( ObjectType );
try {
ExclusiveHandle = FALSE;
if (Attributes & OBJ_EXCLUSIVE) {
if ((Attributes & OBJ_INHERIT) ||
((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
return( Status = STATUS_INVALID_PARAMETER );
}
if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
ObjectHeader->HandleCount != 0
) ||
((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()
)
) {
return( Status = STATUS_ACCESS_DENIED );
}
ExclusiveHandle = TRUE;
}
else
if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) {
return( Status = STATUS_ACCESS_DENIED );
}
//
// If handle count going from zero to one for an existing object that
// maintains a handle count database, but does not have an open procedure
// just a close procedure, then fail the call as they are trying to
// reopen an object by pointer and the close procedure will not know
// that the object has been 'recreated'
//
if (ObjectHeader->HandleCount == 0 &&
!NewObject &&
ObjectType->TypeInfo.MaintainHandleCount &&
ObjectType->TypeInfo.OpenProcedure == NULL &&
ObjectType->TypeInfo.CloseProcedure != NULL
) {
return( Status = STATUS_UNSUCCESSFUL );
}
if ((OpenReason == ObOpenHandle) ||
((OpenReason == ObDuplicateHandle) && ARGUMENT_PRESENT(AccessState))) {
//
// Perform Access Validation to see if we can open this
// (already existing) object.
//
if (!ObCheckObjectAccess( Object,
AccessState,
TRUE,
AccessMode,
&Status )) {
return( Status );
}
}
else
if ((OpenReason == ObCreateHandle)) {
//
// We are creating a new instance of this object type.
// A total of three audit messages may be generated:
//
// 1 - Audit the attempt to create an instance of this
// object type.
//
// 2 - Audit the successful creation.
//
// 3 - Audit the allocation of the handle.
//
//
// At this point, the RemainingDesiredAccess field in
// the AccessState may still contain either Generic access
// types, or MAXIMUM_ALLOWED. We will map the generics
// and substitute GenericAll for MAXIMUM_ALLOWED.
//
if ( AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED ) {
AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
AccessState->RemainingDesiredAccess |= GENERIC_ALL;
}
if ((GENERIC_ACCESS & AccessState->RemainingDesiredAccess) != 0) {
RtlMapGenericMask( &AccessState->RemainingDesiredAccess,
&ObjectType->TypeInfo.GenericMapping
);
}
//
// Since we are creating the object, we can give any access the caller
// wants. The only exception is ACCESS_SYSTEM_SECURITY, which requires
// a privilege.
//
if ( AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY ) {
//
// We could use SeSinglePrivilegeCheck here, but it
// captures the subject context again, and we don't
// want to do that in this path for performance reasons.
//
Privileges.PrivilegeCount = 1;
Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
Privileges.Privilege[0].Luid = SeSecurityPrivilege;
Privileges.Privilege[0].Attributes = 0;
HasPrivilege = SePrivilegeCheck(
&Privileges,
&AccessState->SubjectSecurityContext,
KeGetPreviousMode()
);
if (!HasPrivilege) {
SePrivilegedServiceAuditAlarm ( NULL,
&AccessState->SubjectSecurityContext,
&Privileges,
FALSE
);
return( Status = STATUS_PRIVILEGE_NOT_HELD );
}
AccessState->RemainingDesiredAccess &= ~ACCESS_SYSTEM_SECURITY;
AccessState->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
(VOID)
SeAppendPrivileges(
AccessState,
&Privileges
);
}
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
if (CreatorInfo != NULL) {
InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
}
}
if (ExclusiveHandle) {
OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
}
ObpIncrHandleCount( ObjectHeader );
ProcessHandleCount = 0;
if (ObjectType->TypeInfo.MaintainHandleCount) {
Status = ObpIncrementHandleDataBase( ObjectHeader,
Process,
&ProcessHandleCount );
if (!NT_SUCCESS(Status)) {
leave;
}
}
if (ObjectType->TypeInfo.OpenProcedure != NULL) {
KIRQL SaveIrql;
ObpBeginTypeSpecificCallOut( SaveIrql );
(*ObjectType->TypeInfo.OpenProcedure)( OpenReason,
Process,
Object,
AccessState ?
AccessState->PreviouslyGrantedAccess :
0,
ProcessHandleCount
);
ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
}
ObjectType->TotalNumberOfHandles += 1;
if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) {
ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles;
}
Status = STATUS_SUCCESS;
}
finally {
ObpLeaveObjectTypeMutex( ObjectType );
}
return( Status );
}
NTSTATUS
ObpIncrementUnnamedHandleCount(
PACCESS_MASK DesiredAccess,
PEPROCESS Process,
PVOID Object,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
ULONG Attributes
)
/*++
Routine Description:
Increments the count of number of handles to the given object.
Arguments:
OpenReason - Supplies the reason the handle count is being incremented.
Process - Pointer to the process in which the new handle will reside.
ObjectHeader - Supplies the header to the object.
ObjectType - Supplies the type of the object.
Attributes -
Return Value:
--*/
{
NTSTATUS Status;
BOOLEAN ExclusiveHandle;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
POBJECT_HEADER ObjectHeader;
BOOLEAN NewObject;
ULONG ProcessHandleCount;
PAGED_CODE();
ObpValidateIrql( "ObpIncrementUnnamedHandleCount" );
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
Status = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &NewObject );
if (!NT_SUCCESS( Status )) {
return Status;
}
ObpEnterObjectTypeMutex( ObjectType );
try {
ExclusiveHandle = FALSE;
if (Attributes & OBJ_EXCLUSIVE) {
if ((Attributes & OBJ_INHERIT) ||
((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) == 0)) {
return( Status = STATUS_INVALID_PARAMETER );
}
if (((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) == NULL) &&
ObjectHeader->HandleCount != 0
) ||
((OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) &&
OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != PsGetCurrentProcess()
)
) {
return( Status = STATUS_ACCESS_DENIED );
}
ExclusiveHandle = TRUE;
}
else
if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT) &&
OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader) != NULL) {
return( Status = STATUS_ACCESS_DENIED );
}
//
// If handle count going from zero to one for an existing object that
// maintains a handle count database, but does not have an open procedure
// just a close procedure, then fail the call as they are trying to
// reopen an object by pointer and the close procedure will not know
// that the object has been 'recreated'
//
if (ObjectHeader->HandleCount == 0 &&
!NewObject &&
ObjectType->TypeInfo.MaintainHandleCount &&
ObjectType->TypeInfo.OpenProcedure == NULL &&
ObjectType->TypeInfo.CloseProcedure != NULL
) {
Status = STATUS_UNSUCCESSFUL;
leave;
}
if ( *DesiredAccess & MAXIMUM_ALLOWED ) {
*DesiredAccess &= ~MAXIMUM_ALLOWED;
*DesiredAccess |= GENERIC_ALL;
}
if ((GENERIC_ACCESS & *DesiredAccess) != 0) {
RtlMapGenericMask( DesiredAccess,
&ObjectType->TypeInfo.GenericMapping
);
}
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
if (CreatorInfo != NULL) {
InsertTailList( &ObjectType->TypeList, &CreatorInfo->TypeList );
}
if (ExclusiveHandle) {
OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
}
ObpIncrHandleCount( ObjectHeader );
ProcessHandleCount = 0;
if (ObjectType->TypeInfo.MaintainHandleCount) {
Status = ObpIncrementHandleDataBase( ObjectHeader,
Process,
&ProcessHandleCount );
if (!NT_SUCCESS(Status)) {
leave;
}
}
if (ObjectType->TypeInfo.OpenProcedure != NULL) {
KIRQL SaveIrql;
ObpBeginTypeSpecificCallOut( SaveIrql );
(*ObjectType->TypeInfo.OpenProcedure)( ObCreateHandle,
Process,
Object,
*DesiredAccess,
ProcessHandleCount
);
ObpEndTypeSpecificCallOut( SaveIrql, "Open", ObjectType, Object );
}
ObjectType->TotalNumberOfHandles += 1;
if (ObjectType->TotalNumberOfHandles > ObjectType->HighWaterNumberOfHandles) {
ObjectType->HighWaterNumberOfHandles = ObjectType->TotalNumberOfHandles;
}
Status = STATUS_SUCCESS;
}
finally {
ObpLeaveObjectTypeMutex( ObjectType );
}
return( Status );
}
NTSTATUS
ObpChargeQuotaForObject(
IN POBJECT_HEADER ObjectHeader,
IN POBJECT_TYPE ObjectType,
OUT PBOOLEAN NewObject
)
{
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
ULONG NonPagedPoolCharge;
ULONG PagedPoolCharge;
QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
*NewObject = FALSE;
if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {
ObjectHeader->Flags &= ~OB_FLAG_NEW_OBJECT;
if (QuotaInfo != NULL) {
PagedPoolCharge = QuotaInfo->PagedPoolCharge +
QuotaInfo->SecurityDescriptorCharge;
NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
}
else {
PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
if (ObjectHeader->SecurityDescriptor != NULL) {
ObjectHeader->Flags |= OB_FLAG_DEFAULT_SECURITY_QUOTA;
PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
}
NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
}
ObjectHeader->QuotaBlockCharged = (PVOID)PsChargeSharedPoolQuota( PsGetCurrentProcess(),
PagedPoolCharge,
NonPagedPoolCharge
);
if (ObjectHeader->QuotaBlockCharged == NULL) {
return STATUS_QUOTA_EXCEEDED;
}
*NewObject = TRUE;
}
return STATUS_SUCCESS;
}
VOID
ObpDecrementHandleCount(
PEPROCESS Process,
POBJECT_HEADER ObjectHeader,
POBJECT_TYPE ObjectType,
ACCESS_MASK GrantedAccess
)
{
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase;
POBJECT_HANDLE_COUNT_ENTRY HandleCountEntry;
PVOID Object;
ULONG CountEntries;
ULONG ProcessHandleCount;
ULONG SystemHandleCount;
PAGED_CODE();
ObpEnterObjectTypeMutex( ObjectType );
Object = (PVOID)&ObjectHeader->Body;
SystemHandleCount = ObjectHeader->HandleCount;
ProcessHandleCount = 0;
if (ObpDecrHandleCount( ObjectHeader ) &&
(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE_OBJECT)) {
OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader )->ExclusiveProcess = NULL;
}
if (ObjectType->TypeInfo.MaintainHandleCount) {
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader );
if (ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) {
ASSERT(HandleInfo->SingleEntry.Process == Process);
ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
HandleCountEntry = &HandleInfo->SingleEntry;
}
else {
HandleCountDataBase = HandleInfo->HandleCountDataBase;
if (HandleCountDataBase != NULL) {
CountEntries = HandleCountDataBase->CountEntries;
HandleCountEntry = &HandleCountDataBase->HandleCountEntries[ 0 ];
while (CountEntries) {
if (HandleCountEntry->HandleCount != 0 &&
HandleCountEntry->Process == Process
) {
ProcessHandleCount = HandleCountEntry->HandleCount--;
break;
}
HandleCountEntry++;
CountEntries--;
}
}
}
if (ProcessHandleCount == 1) {
HandleCountEntry->Process = NULL;
HandleCountEntry->HandleCount = 0;
}
}
//
// If the Object Type has a Close Procedure, then release the type
// mutex before calling it, and then call ObpDeleteNameCheck without
// the mutex held.
//
if (ObjectType->TypeInfo.CloseProcedure) {
KIRQL SaveIrql;
ObpLeaveObjectTypeMutex( ObjectType );
ObpBeginTypeSpecificCallOut( SaveIrql );
(*ObjectType->TypeInfo.CloseProcedure)( Process,
Object,
GrantedAccess,
ProcessHandleCount,
SystemHandleCount
);
ObpEndTypeSpecificCallOut( SaveIrql, "Close", ObjectType, Object );
ObpDeleteNameCheck( Object, FALSE );
}
//
// If there is no Close Procedure, then just call ObpDeleteNameCheck
// with the mutex held.
//
else {
//
// The following call will release the type mutex
//
ObpDeleteNameCheck( Object, TRUE );
}
ObjectType->TotalNumberOfHandles -= 1;
}
NTSTATUS
ObpCreateHandle(
IN OB_OPEN_REASON OpenReason,
IN PVOID Object,
IN POBJECT_TYPE ExpectedObjectType OPTIONAL,
IN PACCESS_STATE AccessState,
IN ULONG ObjectPointerBias OPTIONAL,
IN ULONG Attributes,
IN BOOLEAN DirectoryLocked,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *ReferencedNewObject OPTIONAL,
OUT PHANDLE Handle
)
/*++
Routine Description:
description-of-function.
Arguments:
OpenReason -
Object -
ExpectedObjectType -
AccessState -
ObjectPointerBias -
Attributes -
DirectoryLocked -
AccessMode -
ReferencedNewObject -
Handle -
Return Value:
return-value - Description of conditions needed to return value. - or -
None.
--*/
{
NTSTATUS Status;
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
PVOID ObjectTable;
OBJECT_TABLE_ENTRY ObjectTableEntry;
HANDLE NewHandle;
ACCESS_MASK DesiredAccess;
ACCESS_MASK GrantedAccess;
ULONG BiasCount;
PAGED_CODE();
ObpValidateIrql( "ObpCreateHandle" );
DesiredAccess = AccessState->RemainingDesiredAccess |
AccessState->PreviouslyGrantedAccess;
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
ObjectType = ObjectHeader->Type;
if (ARGUMENT_PRESENT( ExpectedObjectType ) &&
ObjectType != ExpectedObjectType
) {
if (DirectoryLocked) {
ObpLeaveRootDirectoryMutex();
}
return( STATUS_OBJECT_TYPE_MISMATCH );
}
ObjectTableEntry.ObjectHeader = ObjectHeader;
ObjectTable = ObpGetObjectTable();
//
// ObpIncrementHandleCount will perform access checking on the
// object being opened as appropriate.
//
Status = ObpIncrementHandleCount( OpenReason,
PsGetCurrentProcess(),
Object,
ObjectType,
AccessState,
AccessMode,
Attributes
);
if (AccessState->GenerateOnClose) {
Attributes |= OBJ_AUDIT_OBJECT_CLOSE;
}
ObjectTableEntry.Attributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
DesiredAccess = AccessState->RemainingDesiredAccess |
AccessState->PreviouslyGrantedAccess;
GrantedAccess = DesiredAccess &
(ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY );
if (DirectoryLocked) {
ObpLeaveRootDirectoryMutex();
}
if (!NT_SUCCESS( Status )) {
return( Status );
}
if (ARGUMENT_PRESENT( ObjectPointerBias )) {
BiasCount = ObjectPointerBias;
while (BiasCount--) {
ObpIncrPointerCount( ObjectHeader );
}
}
#if i386 && !FPO
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
}
else
#endif // i386 && !FPO
ObjectTableEntry.GrantedAccess = GrantedAccess;
NewHandle = ExCreateHandle( ObjectTable, (PHANDLE_ENTRY)&ObjectTableEntry );
if (NewHandle == NULL) {
if (ARGUMENT_PRESENT( ObjectPointerBias )) {
BiasCount = ObjectPointerBias;
while (BiasCount--) {
ObpDecrPointerCount( ObjectHeader );
}
}
ObpDecrementHandleCount( PsGetCurrentProcess(),
ObjectHeader,
ObjectType,
GrantedAccess
);
return( STATUS_INSUFFICIENT_RESOURCES );
}
*Handle = MAKE_OBJECT_HANDLE( NewHandle );
//
// If requested, generate audit messages to indicate that a new handle
// has been allocated.
//
// This is the final security operation in the creation/opening of the
// object.
//
if ( AccessState->GenerateAudit ) {
SeAuditHandleCreation(
AccessState,
*Handle
);
}
if (OpenReason == ObCreateHandle) {
PAUX_ACCESS_DATA AuxData = AccessState->AuxData;
if ( ( AuxData->PrivilegesUsed != NULL) && (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
SePrivilegeObjectAuditAlarm(
*Handle,
&AccessState->SubjectSecurityContext,
GrantedAccess,
AuxData->PrivilegesUsed,
TRUE,
KeGetPreviousMode()
);
}
}
if (ARGUMENT_PRESENT( ObjectPointerBias ) &&
ARGUMENT_PRESENT( ReferencedNewObject )
) {
*ReferencedNewObject = Object;
}
return( STATUS_SUCCESS );
}
NTSTATUS
ObpCreateUnnamedHandle(
IN PVOID Object,
IN ACCESS_MASK DesiredAccess,
IN ULONG ObjectPointerBias OPTIONAL,
IN ULONG Attributes,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *ReferencedNewObject OPTIONAL,
OUT PHANDLE Handle
)
/*++
Routine Description:
description-of-function.
Arguments:
OpenReason -
Object -
ExpectedObjectType -
AccessState -
ObjectPointerBias -
Attributes -
DirectoryLocked -
AccessMode -
ReferencedNewObject -
Handle -
Return Value:
return-value - Description of conditions needed to return value. - or -
None.
--*/
{
NTSTATUS Status;
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
PVOID ObjectTable;
OBJECT_TABLE_ENTRY ObjectTableEntry;
HANDLE NewHandle;
ULONG BiasCount;
ACCESS_MASK GrantedAccess;
PAGED_CODE();
ObpValidateIrql( "ObpCreateUnnamedHandle" );
ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
ObjectType = ObjectHeader->Type;
ObjectTableEntry.ObjectHeader = ObjectHeader;
ObjectTableEntry.Attributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
ObjectTable = ObpGetObjectTable();
Status = ObpIncrementUnnamedHandleCount( &DesiredAccess,
PsGetCurrentProcess(),
Object,
ObjectType,
AccessMode,
Attributes
);
GrantedAccess = DesiredAccess &
(ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY );
if (!NT_SUCCESS( Status )) {
return( Status );
}
if (ARGUMENT_PRESENT( ObjectPointerBias )) {
BiasCount = ObjectPointerBias;
while (BiasCount--) {
ObpIncrPointerCount( ObjectHeader );
}
}
#if i386 && !FPO
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
}
else
#endif // i386 && !FPO
ObjectTableEntry.GrantedAccess = GrantedAccess;
NewHandle = ExCreateHandle( ObjectTable, (PHANDLE_ENTRY)&ObjectTableEntry );
if (NewHandle == NULL) {
if (ARGUMENT_PRESENT( ObjectPointerBias )) {
BiasCount = ObjectPointerBias;
while (BiasCount--) {
ObpDecrPointerCount( ObjectHeader );
}
}
ObpDecrementHandleCount( PsGetCurrentProcess(),
ObjectHeader,
ObjectType,
GrantedAccess
);
return( STATUS_INSUFFICIENT_RESOURCES );
}
*Handle = MAKE_OBJECT_HANDLE( NewHandle );
if (ARGUMENT_PRESENT( ObjectPointerBias ) &&
ARGUMENT_PRESENT( ReferencedNewObject )
) {
*ReferencedNewObject = Object;
}
return( STATUS_SUCCESS );
}
NTSTATUS
NtDuplicateObject(
IN HANDLE SourceProcessHandle,
IN HANDLE SourceHandle,
IN HANDLE TargetProcessHandle OPTIONAL,
OUT PHANDLE TargetHandle OPTIONAL,
IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
IN ULONG Options
)
/*++
Routine Description:
This function creates a handle that is a duplicate of the specified
source handle. The source handle is evaluated in the context of the
specified source process. The calling process must have
PROCESS_DUP_HANDLE access to the source process. The duplicate
handle is created with the specified attributes and desired access.
The duplicate handle is created in the handle table of the specified
target process. The calling process must have PROCESS_DUP_HANDLE
access to the target process.
Arguments:
SourceProcessHandle -
SourceHandle -
TargetProcessHandle -
TargetHandle -
DesiredAccess -
HandleAttributes -
Return Value:
TBS
--*/
{
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PVOID SourceObject;
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
PEPROCESS SourceProcess;
PEPROCESS TargetProcess;
BOOLEAN Attached;
PVOID ObjectTable;
OBJECT_TABLE_ENTRY ObjectTableEntry;
OBJECT_HANDLE_INFORMATION HandleInformation;
HANDLE NewHandle;
ACCESS_STATE AccessState;
AUX_ACCESS_DATA AuxData;
ACCESS_MASK SourceAccess;
ACCESS_MASK TargetAccess;
PACCESS_STATE PassedAccessState = NULL;
//
// Get previous processor mode and probe output arguments if necessary.
//
PreviousMode = KeGetPreviousMode();
if (ARGUMENT_PRESENT( TargetHandle ) && PreviousMode != KernelMode) {
try {
ProbeForWriteHandle( TargetHandle );
}
except( EXCEPTION_EXECUTE_HANDLER ) {
return( GetExceptionCode() );
}
}
if (!(Options & DUPLICATE_SAME_ACCESS)) {
Status = ObpValidateDesiredAccess( DesiredAccess );
if (!NT_SUCCESS( Status )) {
return( Status );
}
}
Attached = FALSE;
Status = ObReferenceObjectByHandle( SourceProcessHandle,
PROCESS_DUP_HANDLE,
PsProcessType,
PreviousMode,
(PVOID *)&SourceProcess,
NULL
);
if (!NT_SUCCESS( Status )) {
return Status;
}
KeEnterCriticalRegion();
KeWaitForSingleObject( &ObpInitKillMutant,
Executive,
KernelMode,
FALSE,
NULL
);
//
// Make sure the source process has an object table still
//
if ( SourceProcess->ObjectTable == NULL ) {
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceProcess );
return STATUS_PROCESS_IS_TERMINATING;
}
//
// If the specified source process is not the current process, attach
// to the specified source process.
//
if (PsGetCurrentProcess() != SourceProcess) {
KeAttachProcess( &SourceProcess->Pcb );
Attached = TRUE;
}
Status = ObReferenceObjectByHandle( SourceHandle,
0,
(POBJECT_TYPE)NULL,
PreviousMode,
&SourceObject,
&HandleInformation
);
if (Attached) {
KeDetachProcess();
Attached = FALSE;
}
if (!NT_SUCCESS( Status )) {
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceProcess );
return( Status );
}
//
// All done if no target process handle specified.
//
if (!ARGUMENT_PRESENT( TargetProcessHandle )) {
//
// If no TargetProcessHandle, then only possible option is to close
// the source handle in the context of the source process.
//
if (!(Options & DUPLICATE_CLOSE_SOURCE)) {
Status = STATUS_INVALID_PARAMETER;
}
if (Options & DUPLICATE_CLOSE_SOURCE) {
KeAttachProcess( &SourceProcess->Pcb );
NtClose( SourceHandle );
KeDetachProcess();
}
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceObject );
ObDereferenceObject( SourceProcess );
return( Status );
}
SourceAccess = HandleInformation.GrantedAccess;
Status = ObReferenceObjectByHandle( TargetProcessHandle,
PROCESS_DUP_HANDLE,
PsProcessType,
PreviousMode,
(PVOID *)&TargetProcess,
NULL
);
if (!NT_SUCCESS( Status )) {
if (Options & DUPLICATE_CLOSE_SOURCE) {
KeAttachProcess( &SourceProcess->Pcb );
NtClose( SourceHandle );
KeDetachProcess();
}
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceObject );
ObDereferenceObject( SourceProcess );
return( Status );
}
//
// Make sure the target process has not exited
//
if ( TargetProcess->ObjectTable == NULL ) {
if (Options & DUPLICATE_CLOSE_SOURCE) {
KeAttachProcess( &SourceProcess->Pcb );
NtClose( SourceHandle );
KeDetachProcess();
}
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceObject );
ObDereferenceObject( SourceProcess );
ObDereferenceObject( TargetProcess );
return STATUS_PROCESS_IS_TERMINATING;
}
//
// If the specified target process is not the current process, attach
// to the specified target process.
//
if (PsGetCurrentProcess() != TargetProcess) {
KeAttachProcess( &TargetProcess->Pcb );
Attached = TRUE;
}
if (Options & DUPLICATE_SAME_ACCESS) {
DesiredAccess = SourceAccess;
}
if (Options & DUPLICATE_SAME_ATTRIBUTES) {
HandleAttributes = HandleInformation.HandleAttributes;
}
else {
//
// Always propogate auditing information.
//
HandleAttributes |= HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE;
}
ObjectHeader = OBJECT_TO_OBJECT_HEADER( SourceObject );
ObjectType = ObjectHeader->Type;
ObjectTableEntry.ObjectHeader = ObjectHeader;
ObjectTableEntry.Attributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
if ((DesiredAccess & GENERIC_ACCESS) != 0) {
RtlMapGenericMask( &DesiredAccess,
&ObjectType->TypeInfo.GenericMapping
);
}
//
// Make sure to preserve ACCESS_SYSTEM_SECURITY, which most likely is not
// found in the ValidAccessMask
//
TargetAccess = DesiredAccess &
(ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY);
//
// If the access requested for the target is a superset of the
// access allowed in the source, perform full AVR. If it is a
// subset or equal, do not perform any access validation.
//
// Do not allow superset access if object type has a private security
// method, as there is no means to call them in this case to do the
// access check.
//
// If the AccessState is not passed to ObpIncrementHandleCount
// there will be no AVR.
//
if (TargetAccess & ~SourceAccess) {
if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod) {
Status = SeCreateAccessState(
&AccessState,
&AuxData,
TargetAccess, // DesiredAccess
&ObjectType->TypeInfo.GenericMapping
);
PassedAccessState = &AccessState;
}
else {
Status = STATUS_ACCESS_DENIED;
}
}
else {
//
// Do not perform AVR
//
PassedAccessState = NULL;
Status = STATUS_SUCCESS;
}
if ( NT_SUCCESS( Status )) {
Status = ObpIncrementHandleCount( ObDuplicateHandle,
PsGetCurrentProcess(),
SourceObject,
ObjectType,
PassedAccessState,
PreviousMode,
HandleAttributes
);
ObjectTable = ObpGetObjectTable();
ASSERT(ObjectTable);
}
if (Attached) {
KeDetachProcess();
Attached = FALSE;
}
if (Options & DUPLICATE_CLOSE_SOURCE) {
KeAttachProcess( &SourceProcess->Pcb );
NtClose( SourceHandle );
KeDetachProcess();
}
if (!NT_SUCCESS( Status )) {
if (PassedAccessState != NULL) {
SeDeleteAccessState( PassedAccessState );
}
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceObject );
ObDereferenceObject( SourceProcess );
ObDereferenceObject( TargetProcess );
return( Status );
}
if (PassedAccessState != NULL && PassedAccessState->GenerateOnClose == TRUE) {
//
// If we performed AVR opening the handle, then mark the handle as needing
// auditing when it's closed.
//
ObjectTableEntry.Attributes |= OBJ_AUDIT_OBJECT_CLOSE;
}
#if i386 && !FPO
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( TargetAccess );
ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
}
else
#endif // i386 && !FPO
ObjectTableEntry.GrantedAccess = TargetAccess;
NewHandle = ExCreateHandle( ObjectTable, (PHANDLE_ENTRY)&ObjectTableEntry );
if (NewHandle) {
//
// Audit the creation of the new handle if AVR was done.
//
if (PassedAccessState != NULL) {
SeAuditHandleCreation( PassedAccessState, MAKE_OBJECT_HANDLE( NewHandle ));
}
if (SeDetailedAuditing && (ObjectTableEntry.Attributes & OBJ_AUDIT_OBJECT_CLOSE)) {
SeAuditHandleDuplication(
SourceHandle,
MAKE_OBJECT_HANDLE( NewHandle ),
SourceProcess,
TargetProcess
);
}
if (ARGUMENT_PRESENT( TargetHandle )) {
try {
*TargetHandle = MAKE_OBJECT_HANDLE( NewHandle );
}
except( EXCEPTION_EXECUTE_HANDLER ) {
//
// Fall through, since we cannot undo what we have done.
//
}
}
}
else {
ObpDecrementHandleCount( TargetProcess,
ObjectHeader,
ObjectType,
TargetAccess
);
ObDereferenceObject( SourceObject );
if (ARGUMENT_PRESENT( TargetHandle )) {
try {
*TargetHandle = (HANDLE)NULL;
}
except( EXCEPTION_EXECUTE_HANDLER ) {
//
// Fall through so we can return the correct status.
//
}
}
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if (PassedAccessState != NULL) {
SeDeleteAccessState( PassedAccessState );
}
KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
KeLeaveCriticalRegion();
ObDereferenceObject( SourceProcess );
ObDereferenceObject( TargetProcess );
return( Status );
}
NTSTATUS
ObpValidateDesiredAccess(
IN ACCESS_MASK DesiredAccess
)
{
if (DesiredAccess & 0x0EE00000) {
return( STATUS_ACCESS_DENIED );
}
else {
return( STATUS_SUCCESS );
}
}
NTSTATUS
ObpCaptureHandleInformation(
IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
IN HANDLE UniqueProcessId,
IN PVOID HandleTableEntry,
IN HANDLE HandleIndex,
IN ULONG Length,
IN OUT PULONG RequiredLength
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,ObGetHandleInformation)
#endif
NTSTATUS
ObpCaptureHandleInformation(
IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo,
IN HANDLE UniqueProcessId,
IN PVOID HandleTableEntry,
IN HANDLE HandleIndex,
IN ULONG Length,
IN OUT PULONG RequiredLength
)
{
NTSTATUS Status;
POBJECT_TABLE_ENTRY ObjectTableEntry = (POBJECT_TABLE_ENTRY)HandleTableEntry;
POBJECT_HEADER ObjectHeader;
*RequiredLength += sizeof( SYSTEM_HANDLE_TABLE_ENTRY_INFO );
if (Length < *RequiredLength) {
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else {
ObjectHeader = (POBJECT_HEADER)
(ObjectTableEntry->Attributes & ~OBJ_HANDLE_ATTRIBUTES);
(*HandleEntryInfo)->UniqueProcessId = (USHORT)UniqueProcessId;
(*HandleEntryInfo)->HandleAttributes = (UCHAR)
(ObjectTableEntry->Attributes & OBJ_HANDLE_ATTRIBUTES);
(*HandleEntryInfo)->ObjectTypeIndex = (UCHAR)(ObjectHeader->Type->Index);
(*HandleEntryInfo)->HandleValue = (USHORT)(MAKE_OBJECT_HANDLE( HandleIndex ));
(*HandleEntryInfo)->Object = &ObjectHeader->Body;
(*HandleEntryInfo)->CreatorBackTraceIndex = 0;
#if i386 && !FPO
if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
(*HandleEntryInfo)->CreatorBackTraceIndex = ObjectTableEntry->CreatorBackTraceIndex;
(*HandleEntryInfo)->GrantedAccess = ObpTranslateGrantedAccessIndex( ObjectTableEntry->GrantedAccessIndex );
}
else
#endif // i386 && !FPO
(*HandleEntryInfo)->GrantedAccess = ObjectTableEntry->GrantedAccess;
(*HandleEntryInfo)++;
Status = STATUS_SUCCESS;
}
return( Status );
}
NTSTATUS
ObGetHandleInformation(
OUT PSYSTEM_HANDLE_INFORMATION HandleInformation,
IN ULONG Length,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS Status;
ULONG RequiredLength;
PAGED_CODE();
RequiredLength = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handles );
if (Length < RequiredLength) {
return( STATUS_INFO_LENGTH_MISMATCH );
}
HandleInformation->NumberOfHandles = 0;
Status = ExSnapShotHandleTables( ObpCaptureHandleInformation,
HandleInformation,
Length,
&RequiredLength
);
if (ARGUMENT_PRESENT( ReturnLength )) {
*ReturnLength = RequiredLength;
}
return( Status );
}
#if i386 && !FPO
ULONG ObpXXX1;
ULONG ObpXXX2;
ULONG ObpXXX3;
USHORT
ObpComputeGrantedAccessIndex(
ACCESS_MASK GrantedAccess
)
{
KIRQL OldIrql;
ULONG GrantedAccessIndex, n;
PACCESS_MASK p;
ObpXXX1 += 1;
ExAcquireFastLock( &ObpLock, &OldIrql );
n = ObpCurCachedGrantedAccessIndex;
p = ObpCachedGrantedAccesses;
for (GrantedAccessIndex=0;
GrantedAccessIndex<n;
GrantedAccessIndex++, p++
) {
ObpXXX2 += 1;
if (*p == GrantedAccess) {
ExReleaseFastLock( &ObpLock, OldIrql );
return (USHORT)GrantedAccessIndex;
}
}
if (ObpCurCachedGrantedAccessIndex == ObpMaxCachedGrantedAccessIndex) {
DbgPrint( "OB: GrantedAccess cache limit hit.\n" );
DbgBreakPoint();
}
*p = GrantedAccess;
ObpCurCachedGrantedAccessIndex += 1;
ExReleaseFastLock( &ObpLock, OldIrql );
return (USHORT)GrantedAccessIndex;
}
ACCESS_MASK
ObpTranslateGrantedAccessIndex(
USHORT GrantedAccessIndex
)
{
KIRQL OldIrql;
ACCESS_MASK GrantedAccess = (ACCESS_MASK)0;
ObpXXX3 += 1;
ExAcquireFastLock( &ObpLock, &OldIrql );
if (GrantedAccessIndex < ObpCurCachedGrantedAccessIndex) {
GrantedAccess = ObpCachedGrantedAccesses[ GrantedAccessIndex ];
}
ExReleaseFastLock( &ObpLock, OldIrql );
return GrantedAccess;
}
#endif // i386 && !FPO