1781 lines
50 KiB
C
1781 lines
50 KiB
C
|
/*++
|
|||
|
|
|||
|
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
|