Implement object reference by handle
This commit is contained in:
@@ -18,6 +18,7 @@ namespace OB
|
|||||||
class LifeCycle
|
class LifeCycle
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
STATIC PHANDLE_TABLE KernelHandleTable;
|
||||||
STATIC PVOID RemoveObjectList;
|
STATIC PVOID RemoveObjectList;
|
||||||
STATIC WORK_QUEUE_ITEM RemoveObjectWorkItem;
|
STATIC WORK_QUEUE_ITEM RemoveObjectWorkItem;
|
||||||
|
|
||||||
@@ -40,6 +41,12 @@ namespace OB
|
|||||||
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object);
|
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object);
|
||||||
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object,
|
STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object,
|
||||||
IN ULONG Count);
|
IN ULONG Count);
|
||||||
|
STATIC XTAPI XTSTATUS ReferenceObject(IN HANDLE Handle,
|
||||||
|
IN ACCESS_MASK DesiredAccess,
|
||||||
|
IN POBJECT_TYPE ObjectType,
|
||||||
|
IN KPROCESSOR_MODE AccessMode,
|
||||||
|
OUT PVOID *Object,
|
||||||
|
OUT POBJECT_HANDLE_INFORMATION HandleInformation);
|
||||||
STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO ReferenceObjectNameInformation(IN POBJECT_HEADER ObjectHeader);
|
STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO ReferenceObjectNameInformation(IN POBJECT_HEADER ObjectHeader);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -15,9 +15,21 @@ KPUSH_LOCK OB::DeviceMap::DeviceMapLock;
|
|||||||
/* Indicates whether the system employs unique device maps */
|
/* Indicates whether the system employs unique device maps */
|
||||||
BOOLEAN OB::DeviceMap::UniqueDeviceMaps;
|
BOOLEAN OB::DeviceMap::UniqueDeviceMaps;
|
||||||
|
|
||||||
|
/* Pointer to the system-wide kernel handle table */
|
||||||
|
PHANDLE_TABLE OB::LifeCycle::KernelHandleTable;
|
||||||
|
|
||||||
/* System work queue item responsible for scheduling the deferred object deletion */
|
/* System work queue item responsible for scheduling the deferred object deletion */
|
||||||
WORK_QUEUE_ITEM OB::LifeCycle::RemoveObjectWorkItem;
|
WORK_QUEUE_ITEM OB::LifeCycle::RemoveObjectWorkItem;
|
||||||
|
|
||||||
|
/* The list head for tracking objects that have been marked for deferred deletion */
|
||||||
|
PVOID OB::LifeCycle::RemoveObjectList;
|
||||||
|
|
||||||
|
/* General lookaside list used for allocation and deallocation of OBJECT_CREATE_INFORMATION structures */
|
||||||
|
GENERAL_LOOKASIDE OB::Manager::CreateInfoList;
|
||||||
|
|
||||||
|
/* General lookaside list used for allocation and deallocation buffers for Unicode object names */
|
||||||
|
GENERAL_LOOKASIDE OB::Manager::NameBufferList;
|
||||||
|
|
||||||
/* Default kernel event utilized by the Object Manager */
|
/* Default kernel event utilized by the Object Manager */
|
||||||
KEVENT OB::TypeRegistry::DefaultEvent;
|
KEVENT OB::TypeRegistry::DefaultEvent;
|
||||||
|
|
||||||
@@ -29,12 +41,3 @@ POBJECT_DIRECTORY OB::TypeRegistry::ObjectTypeDirectory;
|
|||||||
|
|
||||||
/* Index-based lookup for all registered object types */
|
/* Index-based lookup for all registered object types */
|
||||||
POBJECT_TYPE OB::TypeRegistry::ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES];
|
POBJECT_TYPE OB::TypeRegistry::ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES];
|
||||||
|
|
||||||
/* General lookaside list used for allocation and deallocation of OBJECT_CREATE_INFORMATION structures */
|
|
||||||
GENERAL_LOOKASIDE OB::Manager::CreateInfoList;
|
|
||||||
|
|
||||||
/* General lookaside list used for allocation and deallocation buffers for Unicode object names */
|
|
||||||
GENERAL_LOOKASIDE OB::Manager::NameBufferList;
|
|
||||||
|
|
||||||
/* The list head for tracking objects that have been marked for deferred deletion */
|
|
||||||
PVOID OB::LifeCycle::RemoveObjectList;
|
|
||||||
|
|||||||
@@ -1386,6 +1386,199 @@ OB::LifeCycle::ReferenceObject(IN PVOID Object,
|
|||||||
return RTL::Atomic::ExchangeAdd64(&ObjectHeader->PointerCount, Count) + Count;
|
return RTL::Atomic::ExchangeAdd64(&ObjectHeader->PointerCount, Count) + Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the pointer reference count on an object provided by a handle.
|
||||||
|
*
|
||||||
|
* @param Handle
|
||||||
|
* Supplies the handle to the object being referenced.
|
||||||
|
*
|
||||||
|
* @param AccessMask
|
||||||
|
* Supplies the access mask representing the requested access rights.
|
||||||
|
*
|
||||||
|
* @param ObjectType
|
||||||
|
* Optionally supplies a pointer to the expected object type to validate against.
|
||||||
|
*
|
||||||
|
* @param ProcessorMode
|
||||||
|
* Supplies the processor mode from which the handle is being accessed.
|
||||||
|
*
|
||||||
|
* @param Object
|
||||||
|
* Receives a pointer to the referenced object body upon success.
|
||||||
|
*
|
||||||
|
* @param HandleInformation
|
||||||
|
* Supplies an optional pointer that receives information regarding the handle's granted access and attributes.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code indicating the success or failure of the operation.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
OB::LifeCycle::ReferenceObject(IN HANDLE Handle,
|
||||||
|
IN ACCESS_MASK AccessMask,
|
||||||
|
IN POBJECT_TYPE ObjectType,
|
||||||
|
IN KPROCESSOR_MODE ProcessorMode,
|
||||||
|
OUT PVOID *Object,
|
||||||
|
OUT POBJECT_HANDLE_INFORMATION HandleInformation)
|
||||||
|
{
|
||||||
|
PHANDLE_TABLE_ENTRY ObjectTableEntry;
|
||||||
|
PHANDLE_TABLE_ENTRY_INFO ObjectInfo;
|
||||||
|
POBJECT_HEADER ObjectHeader;
|
||||||
|
PHANDLE_TABLE HandleTable;
|
||||||
|
ACCESS_MASK GrantedAccess;
|
||||||
|
POBJECT_TYPE PseudoType;
|
||||||
|
PVOID PseudoObject;
|
||||||
|
PEPROCESS Process;
|
||||||
|
PETHREAD Thread;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Initialize the output pointer */
|
||||||
|
*Object = NULLPTR;
|
||||||
|
|
||||||
|
/* Retrieve the current execution context */
|
||||||
|
Thread = PS::Thread::GetCurrentThread();
|
||||||
|
Process = PS::Process::GetCurrentProcess();
|
||||||
|
|
||||||
|
/* Determine if the handle is a special kernel handle or a pseudohandle */
|
||||||
|
if((LONG)(ULONG_PTR)Handle < 0)
|
||||||
|
{
|
||||||
|
/* Check if the handle points to the current process or thread */
|
||||||
|
if(Handle == PS_CURRENT_PROCESS_HANDLE || Handle == PS_CURRENT_THREAD_HANDLE)
|
||||||
|
{
|
||||||
|
/* Check if the handle points to the current process */
|
||||||
|
if(Handle == PS_CURRENT_PROCESS_HANDLE)
|
||||||
|
{
|
||||||
|
/* Bind the execution context to the current process pseudohandle */
|
||||||
|
PseudoObject = (PVOID)Process;
|
||||||
|
PseudoType = PS::ProcessManager::GetProcessType();
|
||||||
|
GrantedAccess = Process->GrantedAccess;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Bind the execution context to the current thread pseudohandle */
|
||||||
|
PseudoObject = (PVOID)Thread;
|
||||||
|
PseudoType = PS::ProcessManager::GetThreadType();
|
||||||
|
GrantedAccess = Thread->GrantedAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate the object type */
|
||||||
|
if(ObjectType && ObjectType != PseudoType)
|
||||||
|
{
|
||||||
|
/* Object type does not match the pseudohandle type, return error code */
|
||||||
|
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enforce security constraints for user-mode requests */
|
||||||
|
if(ProcessorMode != KernelMode && SE::Access::ComputeDeniedAccesses(GrantedAccess, AccessMask))
|
||||||
|
{
|
||||||
|
/* The caller lacks the requested access rights, return error code */
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve the object header */
|
||||||
|
ObjectHeader = CONTAIN_RECORD(PseudoObject, OBJECT_HEADER, Body);
|
||||||
|
|
||||||
|
/* Increment the reference count */
|
||||||
|
RTL::Atomic::Increment64(&ObjectHeader->PointerCount);
|
||||||
|
|
||||||
|
/* Check if handle information is requested */
|
||||||
|
if(HandleInformation)
|
||||||
|
{
|
||||||
|
/* Populate the optional handle information descriptor */
|
||||||
|
HandleInformation->GrantedAccess = GrantedAccess;
|
||||||
|
HandleInformation->HandleAttributes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign the object pointer and return */
|
||||||
|
*Object = PseudoObject;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if request comes from a user-mode */
|
||||||
|
if(ProcessorMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Reject user-mode attempt, return error code */
|
||||||
|
return STATUS_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode the kernel handle and select the system handle table */
|
||||||
|
Handle = OB::Handle::DecodeKernelHandle(Handle);
|
||||||
|
HandleTable = KernelHandleTable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Use the process handle table */
|
||||||
|
HandleTable = Process->ObjectTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enter a critical region */
|
||||||
|
KE::CriticalRegionGuard CriticalRegion(&Thread->ThreadControlBlock);
|
||||||
|
|
||||||
|
/* Map the given handle to its underlying physical table entry */
|
||||||
|
ObjectTableEntry = EX::Handle::MapHandleToPointer(HandleTable, Handle);
|
||||||
|
if(!ObjectTableEntry)
|
||||||
|
{
|
||||||
|
/* The handle is invalid or closed, return error code */
|
||||||
|
return STATUS_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve the object header */
|
||||||
|
ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)ObjectTableEntry->Object) & ~OBJECT_HANDLE_ATTRIBUTES);
|
||||||
|
|
||||||
|
/* Verify object type consistency */
|
||||||
|
if(ObjectType && ObjectHeader->Type != ObjectType)
|
||||||
|
{
|
||||||
|
/* Set status code */
|
||||||
|
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Decode the granted access mask */
|
||||||
|
GrantedAccess = ((ObjectTableEntry->GrantedAccess) & ~OBJECT_ACCESS_PROTECT_CLOSE_BIT);
|
||||||
|
|
||||||
|
/* Verify if the caller possesses the requested access rights */
|
||||||
|
if(ProcessorMode != KernelMode && SE::Access::ComputeDeniedAccesses(GrantedAccess, AccessMask))
|
||||||
|
{
|
||||||
|
/* Set status code */
|
||||||
|
Status = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check if handle information is requested */
|
||||||
|
if(HandleInformation)
|
||||||
|
{
|
||||||
|
/* Populate the optional handle information descriptor */
|
||||||
|
HandleInformation->GrantedAccess = GrantedAccess;
|
||||||
|
HandleInformation->HandleAttributes = OB::Handle::GetHandleAttributes(ObjectTableEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if audit is required */
|
||||||
|
if((ObjectTableEntry->ObAttributes & OBJECT_AUDIT_OBJECT_CLOSE) && AccessMask && ProcessorMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Fetch the handle information */
|
||||||
|
ObjectInfo = EX::Handle::GetHandleInformation(HandleTable, Handle, TRUE);
|
||||||
|
if(ObjectInfo && ObjectInfo->AuditMask)
|
||||||
|
{
|
||||||
|
/* Generate a security audit event */
|
||||||
|
OB::Security::AuditObjectAccess(Handle, ObjectInfo, &ObjectHeader->Type->Name, AccessMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the reference count */
|
||||||
|
RTL::Atomic::Increment64(&ObjectHeader->PointerCount);
|
||||||
|
|
||||||
|
/* Assign the object pointer and mark the operation as successful */
|
||||||
|
*Object = &ObjectHeader->Body;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the handle table */
|
||||||
|
EX::Handle::UnlockHandleTableEntry(HandleTable, ObjectTableEntry);
|
||||||
|
|
||||||
|
/* Return status code */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the query reference count of a NameInfo structure.
|
* Increments the query reference count of a NameInfo structure.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user