448 lines
15 KiB
C++
448 lines
15 KiB
C++
/**
|
|
* PROJECT: ExectOS
|
|
* COPYRIGHT: See COPYING.md in the top level directory
|
|
* FILE: xtoskrnl/ob/typereg.cc
|
|
* DESCRIPTION: Object Manager Type Registry
|
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
|
*/
|
|
|
|
#include <xtos.hh>
|
|
|
|
|
|
/**
|
|
* Creates and initializes a new object type within the Object Manager namespace.
|
|
*
|
|
* @param TypeName
|
|
* Supplies the requested name of the new object type.
|
|
*
|
|
* @param Initializer
|
|
* Supplies the initialization parameters for the new object type.
|
|
*
|
|
* @param SecurityDescriptor
|
|
* Supplies an optional security descriptor. (Currently ignored).
|
|
*
|
|
* @param ObjectType
|
|
* Receives a pointer to the newly created object type.
|
|
*
|
|
* @return This routine returns a status code indicating the success or failure of the operation.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
OB::TypeRegistry::CreateObjectType(IN PUNICODE_STRING TypeName,
|
|
IN POBJECT_TYPE_INITIALIZER Initializer,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
OUT POBJECT_TYPE *ObjectType)
|
|
{
|
|
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
|
OBJECT_LOOKUP_CONTEXT LookupContext;
|
|
POBJECT_HEADER NewObjectTypeHeader;
|
|
POBJECT_TYPE NewObjectType;
|
|
UNICODE_STRING ObjectName;
|
|
XTSTATUS Status;
|
|
|
|
/* Validate incoming parameters */
|
|
Status = ValidateObjectTypeParameters(TypeName, Initializer);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Parameter validation failed, return error code */
|
|
return Status;
|
|
}
|
|
|
|
/* Initialize the lookup context */
|
|
OB::Directory::InitializeLookupContext(&LookupContext);
|
|
|
|
/* Check if the global type directory exists */
|
|
if(ObjectTypeDirectory)
|
|
{
|
|
/* Acquire the directory lock and prepare for namespace lookup */
|
|
OB::Directory::LockLookupContext(ObjectTypeDirectory, &LookupContext);
|
|
|
|
/* Search the directory to check if an object type with this name already exists */
|
|
if(OB::Directory::LookupDirectoryEntry(ObjectTypeDirectory, TypeName, OBJECT_CASE_INSENSITIVE,
|
|
FALSE, &LookupContext))
|
|
{
|
|
/* A collision detected, release the directory lock and lookup context */
|
|
OB::Directory::ReleaseLookupContext(&LookupContext);
|
|
|
|
/* Reject the creation due to a naming conflict */
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
}
|
|
|
|
/* Allocate paged memory for the persistent object type name */
|
|
Status = MM::Allocator::AllocatePool(PagedPool, (ULONG)TypeName->MaximumLength,
|
|
(PVOID*)&ObjectName.Buffer, TAG_OB_NAME);
|
|
if(Status != STATUS_SUCCESS || ObjectName.Buffer == NULLPTR)
|
|
{
|
|
/* Pool allocation failed; release the lookup context and return error code */
|
|
OB::Directory::ReleaseLookupContext(&LookupContext);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Copy the requested type name */
|
|
ObjectName.MaximumLength = TypeName->MaximumLength;
|
|
RTL::Unicode::CopyString(&ObjectName, TypeName);
|
|
|
|
/* Allocate the physical memory block for the Object Type */
|
|
Status = OB::LifeCycle::AllocateObject(NULLPTR, KernelMode, MasterObjectType, &ObjectName,
|
|
sizeof(OBJECT_TYPE), &NewObjectTypeHeader);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Object allocation failed; release the directory lock and free allocated name buffer */
|
|
OB::Directory::ReleaseLookupContext(&LookupContext);
|
|
MM::Allocator::FreePool(ObjectName.Buffer);
|
|
|
|
/* Return error code */
|
|
return Status;
|
|
}
|
|
|
|
/* Resolve the object body pointer and assign the captured name */
|
|
NewObjectTypeHeader->Flags |= OBJECT_FLAG_KERNEL_MODE | OBJECT_FLAG_PERMANENT;
|
|
NewObjectType = (POBJECT_TYPE)&NewObjectTypeHeader->Body;
|
|
NewObjectType->Name = ObjectName;
|
|
|
|
/* Zero out the statistics block */
|
|
RTL::Memory::ZeroMemory(&NewObjectType->TotalNumberOfObjects,
|
|
FIELD_OFFSET(OBJECT_TYPE, TypeInfo) - FIELD_OFFSET(OBJECT_TYPE, TotalNumberOfObjects));
|
|
|
|
/* Check if master object type is already initialized */
|
|
if(MasterObjectType == NULLPTR)
|
|
{
|
|
/* Set the global master type, link its header to itself, and set the default tag */
|
|
MasterObjectType = NewObjectType;
|
|
NewObjectTypeHeader->Type = MasterObjectType;
|
|
NewObjectType->Key = TAG_OB_OBJECT_TYPE;
|
|
NewObjectType->TotalNumberOfObjects = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Generate a clean tag from object name */
|
|
NewObjectType->Key = GenerateObjectPoolTag(TypeName);
|
|
}
|
|
|
|
/* Initialize default objects and pool charges */
|
|
InitializeObjectType(NewObjectType, Initializer, &ObjectName);
|
|
|
|
/* Suspend APCs and acquire exclusive access to the master type tracking list */
|
|
KE::KThread::EnterCriticalRegion();
|
|
KE::PushLock::AcquireExclusivePushLock(&MasterObjectType->TypeLock);
|
|
|
|
/* Retrieve the creator information header */
|
|
CreatorInfo = OB::LifeCycle::GetObjectCreatorInformation(NewObjectTypeHeader);
|
|
if(CreatorInfo != NULLPTR)
|
|
{
|
|
/* Link the new object type */
|
|
RTL::LinkedList::InsertTailList(&MasterObjectType->TypeList, &CreatorInfo->TypeList);
|
|
|
|
/* Prevent double-insertion during handle creation */
|
|
NewObjectTypeHeader->Flags &= ~OBJECT_FLAG_CREATOR_INFO;
|
|
}
|
|
|
|
/* Assign a type index */
|
|
NewObjectType->Index = MasterObjectType->TotalNumberOfObjects;
|
|
if(NewObjectType->Index < OBJECT_MAX_DEFINED_OBJECT_TYPES)
|
|
{
|
|
/* Register the new type in the global table */
|
|
ObjectTypesTable[NewObjectType->Index - 1] = NewObjectType;
|
|
}
|
|
|
|
/* Release the master type lock and restore APC delivery */
|
|
KE::PushLock::ReleaseExclusivePushLock(&MasterObjectType->TypeLock);
|
|
KE::KThread::LeaveCriticalRegion();
|
|
|
|
/* Publish into the namespace directory */
|
|
if(ObjectTypeDirectory == NULLPTR ||
|
|
OB::Directory::InsertDirectoryEntry(ObjectTypeDirectory, &LookupContext, NewObjectTypeHeader))
|
|
{
|
|
/* Verify if the directory is present */
|
|
if(ObjectTypeDirectory)
|
|
{
|
|
/* Increment the reference count */
|
|
OB::LifeCycle::ReferenceObject(ObjectTypeDirectory);
|
|
}
|
|
|
|
/* Release the directory lock and context */
|
|
OB::Directory::ReleaseLookupContext(&LookupContext);
|
|
|
|
/* Return the pointer to the object type */
|
|
*ObjectType = NewObjectType;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Directory insertion failed, release lock and return error code */
|
|
OB::Directory::ReleaseLookupContext(&LookupContext);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cleans up internal resources associated with an object type before its deletion.
|
|
*
|
|
* @param Object
|
|
* Supplies a pointer to the Object Type body being deleted.
|
|
*
|
|
* @return This routine does not return any value.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
VOID
|
|
OB::TypeRegistry::DeleteObjectType(IN PVOID Object)
|
|
{
|
|
/* Nothing to do */
|
|
}
|
|
|
|
/**
|
|
* Generates a 4-byte pool tag based on the object type name.
|
|
*
|
|
* @param TypeName
|
|
* Supplies the name of the object type.
|
|
*
|
|
* @return This routine returns a 32-bit pool tag.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
ULONG
|
|
OB::TypeRegistry::GenerateObjectPoolTag(IN PUNICODE_STRING TypeName)
|
|
{
|
|
ULONG Index, Tag;
|
|
PUCHAR TagBytes;
|
|
|
|
/* Default tag to four spaces */
|
|
Tag = SIGNATURE32(' ', ' ', ' ', ' ');
|
|
TagBytes = (PUCHAR)&Tag;
|
|
|
|
/* Extract up to the first 4 characters */
|
|
for(Index = 0; Index < 4; Index++)
|
|
{
|
|
/* Verify if the current index falls within the valid bounds */
|
|
if(Index < (TypeName->Length / sizeof(WCHAR)))
|
|
{
|
|
/* Strip the high unicode byte and store the resulting ASCII character */
|
|
TagBytes[Index] = (UCHAR)(TypeName->Buffer[Index] & 0xFF);
|
|
}
|
|
}
|
|
|
|
/* Return the tag */
|
|
return Tag;
|
|
}
|
|
|
|
/**
|
|
* Initializes the internal body and configuration of a newly allocated object type.
|
|
*
|
|
* @param ObjectType
|
|
* Supplies a pointer to the object type to initialize.
|
|
*
|
|
* @param Initializer
|
|
* Supplies the initialization parameters.
|
|
*
|
|
* @param TypeName
|
|
* Supplies the name of the object type.
|
|
*
|
|
* @return This routine does not return any value.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
VOID
|
|
OB::TypeRegistry::InitializeObjectType(IN OUT POBJECT_TYPE ObjectType,
|
|
IN POBJECT_TYPE_INITIALIZER Initializer,
|
|
IN PUNICODE_STRING TypeName)
|
|
{
|
|
ULONG HeaderCharge;
|
|
|
|
/* Calculate standard header charges */
|
|
HeaderCharge = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO);
|
|
|
|
/* Verify if the object type requires handle count tracking */
|
|
if(Initializer->MaintainHandleCount)
|
|
{
|
|
/* Include the size of the handle information header in the total charge */
|
|
HeaderCharge += sizeof(OBJECT_HEADER_HANDLE_INFO);
|
|
}
|
|
|
|
/* Copy initialization data */
|
|
RTL::Memory::CopyMemory(&ObjectType->TypeInfo, Initializer, sizeof(OBJECT_TYPE_INITIALIZER));
|
|
|
|
/* Enforce global type list maintenance and configure the target pool type */
|
|
ObjectType->TypeInfo.MaintainTypeList = TRUE;
|
|
ObjectType->TypeInfo.PoolType = Initializer->PoolType;
|
|
|
|
/* Check pool type */
|
|
if(Initializer->PoolType == NonPagedPool)
|
|
{
|
|
/* Apply the charge to the non-paged pool requirement */
|
|
ObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderCharge;
|
|
}
|
|
else
|
|
{
|
|
/* Apply the charge to the paged pool requirement */
|
|
ObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderCharge;
|
|
}
|
|
|
|
/* Check if the caller supplied a custom procedure for security descriptor operations */
|
|
if(Initializer->SecurityProcedure == NULLPTR)
|
|
{
|
|
/* No custom procedure provided, attach the generic system handler */
|
|
ObjectType->TypeInfo.SecurityProcedure = OB::Security::ProcessObjectSecurityDescriptor;
|
|
}
|
|
|
|
/* Initialize synchronization mechanisms */
|
|
KE::PushLock::InitializePushLock(&ObjectType->TypeLock);
|
|
|
|
/* Initialize the queue for registered callbacks and the tracking list */
|
|
RTL::LinkedList::InitializeListHead(&ObjectType->CallbackList);
|
|
RTL::LinkedList::InitializeListHead(&ObjectType->TypeList);
|
|
|
|
/* Check if the object type has a default object */
|
|
if(ObjectType->TypeInfo.UseDefaultObject)
|
|
{
|
|
/* Map to the global default event and append the SYNCHRONIZE access right */
|
|
ObjectType->DefaultObject = &DefaultEvent;
|
|
ObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
|
|
}
|
|
else if(TypeName->Length == 8 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"File", 0))
|
|
{
|
|
/* Point the synchronization offset directly to the internal Event field */
|
|
ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(FILE_OBJECT, Event);
|
|
}
|
|
else if(TypeName->Length == 24 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"WaitablePort", 0))
|
|
{
|
|
/* Point the synchronization offset directly to the WaitEvent field */
|
|
ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(LPCP_PORT_OBJECT, WaitEvent);
|
|
}
|
|
else
|
|
{
|
|
/* Disable synchronization for this object type */
|
|
ObjectType->DefaultObject = NULLPTR;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes the global Object Type Registry and bootstraps the master type object.
|
|
*
|
|
* @return This routine returns a status code indicating the success or failure of the operation.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
OB::TypeRegistry::InitializeObjectTypeRegistry(VOID)
|
|
{
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
UNICODE_STRING TypeName;
|
|
XTSTATUS Status;
|
|
|
|
/* Initialize the global directory pointer */
|
|
ObjectTypeDirectory = NULLPTR;
|
|
|
|
/* Clear the global object type lookup table and the default synchronization event block */
|
|
RTL::Memory::ZeroMemory(ObjectTypesTable, sizeof(ObjectTypesTable));
|
|
RTL::Memory::ZeroMemory(&DefaultEvent, sizeof(KEVENT));
|
|
|
|
/* Clear the initialization structure */
|
|
RTL::Memory::ZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER));
|
|
|
|
/* Configure the attributes and pool charges for the master "Type" object */
|
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
|
|
ObjectTypeInitializer.InvalidAttributes = OBJECT_OPENLINK;
|
|
ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER);
|
|
ObjectTypeInitializer.MaintainTypeList = TRUE;
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
|
|
|
|
/* Register default destructor */
|
|
ObjectTypeInitializer.DeleteProcedure = &DeleteObjectType;
|
|
|
|
/* Initialize the descriptor for the "Type" name */
|
|
RTL::Unicode::InitializeString(&TypeName, L"Type");
|
|
|
|
/* Create the master object type */
|
|
Status = CreateObjectType(&TypeName, &ObjectTypeInitializer, NULLPTR, &MasterObjectType);
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
/* Object type creation failed, return error code */
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Validates the parameters supplied for creating a new object type.
|
|
*
|
|
* @param TypeName
|
|
* Supplies the requested name of the new object type.
|
|
*
|
|
* @param Initializer
|
|
* Supplies the initialization parameters for the new object type.
|
|
*
|
|
* @return This routine returns a status code indicating the success or failure of the operation.
|
|
*
|
|
* @since XT 1.0
|
|
*/
|
|
XTAPI
|
|
XTSTATUS
|
|
OB::TypeRegistry::ValidateObjectTypeParameters(IN PUNICODE_STRING TypeName,
|
|
IN POBJECT_TYPE_INITIALIZER Initializer)
|
|
{
|
|
ULONG Index;
|
|
PWCH Buffer;
|
|
|
|
/* Check the basic string validity and alignment */
|
|
if(TypeName == NULLPTR || TypeName->Length == 0 || (TypeName->Length % sizeof(WCHAR)) != 0)
|
|
{
|
|
/* Invalid type name, return error code */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Check initializer block integrity and allowed flags */
|
|
if(Initializer == NULLPTR ||
|
|
(Initializer->InvalidAttributes & ~OBJECT_VALID_ATTRIBUTES) != 0 ||
|
|
Initializer->Length != sizeof(OBJECT_TYPE_INITIALIZER))
|
|
{
|
|
/* Invalid initializer block, return error code */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Check the maintaining handle count and procedure presence */
|
|
if(Initializer->MaintainHandleCount &&
|
|
Initializer->OpenProcedure == NULLPTR &&
|
|
Initializer->CloseProcedure == NULLPTR)
|
|
{
|
|
/* Invalid initializer block, return error code */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Validate memory pool type */
|
|
if(!Initializer->UseDefaultObject && Initializer->PoolType != NonPagedPool)
|
|
{
|
|
/* Invalid pool type, return error code */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Extract the buffer pointer */
|
|
Buffer = TypeName->Buffer;
|
|
Index = TypeName->Length / sizeof(WCHAR);
|
|
|
|
/* Scan for illegal path separators in the type name */
|
|
while(Index--)
|
|
{
|
|
/* Check for path separator */
|
|
if(*Buffer++ == OBJECT_NAME_PATH_SEPARATOR)
|
|
{
|
|
/* Invalid type name, return error code */
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|