1371 lines
34 KiB
C
1371 lines
34 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
obcreate.c
|
||
|
||
Abstract:
|
||
|
||
Object creation
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 31-Mar-1989
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "obp.h"
|
||
|
||
#undef ObCreateObject
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, ObCreateObject)
|
||
#pragma alloc_text(PAGE, ObpCaptureObjectCreateInformation)
|
||
#pragma alloc_text(PAGE, ObpCaptureObjectName)
|
||
#pragma alloc_text(PAGE, ObpAllocateObjectNameBuffer)
|
||
#pragma alloc_text(PAGE, ObpFreeObjectNameBuffer)
|
||
#pragma alloc_text(PAGE, ObDeleteCapturedInsertInfo)
|
||
#pragma alloc_text(PAGE, ObpAllocateObject)
|
||
#pragma alloc_text(PAGE, ObpFreeObject)
|
||
#pragma alloc_text(PAGE, ObFreeObjectCreateInfoBuffer)
|
||
#endif
|
||
|
||
|
||
#if DBG
|
||
|
||
BOOLEAN ObWatchHandles = FALSE;
|
||
|
||
//
|
||
// The following variable is only used on a checked build to control
|
||
// echoing out the allocs and frees of objects
|
||
//
|
||
|
||
BOOLEAN ObpShowAllocAndFree;
|
||
#else
|
||
|
||
const BOOLEAN ObWatchHandles = FALSE;
|
||
|
||
#endif
|
||
|
||
//
|
||
// Local performance counters
|
||
//
|
||
|
||
#if DBG
|
||
ULONG ObpObjectsCreated;
|
||
ULONG ObpObjectsWithPoolQuota;
|
||
ULONG ObpObjectsWithHandleDB;
|
||
ULONG ObpObjectsWithName;
|
||
ULONG ObpObjectsWithCreatorInfo;
|
||
#endif // DBG
|
||
|
||
C_ASSERT ( (FIELD_OFFSET (OBJECT_HEADER, Body) % MEMORY_ALLOCATION_ALIGNMENT) == 0 );
|
||
C_ASSERT ( (sizeof (OBJECT_HEADER_CREATOR_INFO) % MEMORY_ALLOCATION_ALIGNMENT) == 0 );
|
||
C_ASSERT ( (sizeof (OBJECT_HEADER_NAME_INFO) % MEMORY_ALLOCATION_ALIGNMENT) == 0 );
|
||
C_ASSERT ( (sizeof (OBJECT_HEADER_QUOTA_INFO) % MEMORY_ALLOCATION_ALIGNMENT) == 0 );
|
||
|
||
|
||
NTSTATUS
|
||
ObCreateObject (
|
||
IN KPROCESSOR_MODE ProbeMode,
|
||
IN POBJECT_TYPE ObjectType,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
||
IN KPROCESSOR_MODE OwnershipMode,
|
||
IN OUT PVOID ParseContext OPTIONAL,
|
||
IN ULONG ObjectBodySize,
|
||
IN ULONG PagedPoolCharge,
|
||
IN ULONG NonPagedPoolCharge,
|
||
OUT PVOID *Object
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This functions allocates space for an NT Object from either
|
||
Paged or NonPaged pool. It captures the optional name and
|
||
SECURITY_DESCRIPTOR parameters for later use when the object is
|
||
inserted into an object table. No quota is charged at this time.
|
||
That occurs when the object is inserted into an object table.
|
||
|
||
Arguments:
|
||
|
||
ProbeMode - The processor mode to consider when doing a probe
|
||
of the input parameters
|
||
|
||
ObjectType - A pointer of the type returned by ObCreateObjectType
|
||
that gives the type of object being created.
|
||
|
||
ObjectAttributes - Optionally supplies the attributes of the object
|
||
being created (such as its name)
|
||
|
||
OwnershipMode - The processor mode of who is going to own the object
|
||
|
||
ParseContext - Ignored
|
||
|
||
ObjectBodySize - Number of bytes to allocate for the object body. The
|
||
object body immediately follows the object header in memory and are
|
||
part of a single allocation.
|
||
|
||
PagedPoolCharge - Supplies the amount of paged pool to charge for the
|
||
object. If zero is specified then the default charge for the object
|
||
type is used.
|
||
|
||
NonPagedPoolCharge - Supplies the amount of nonpaged pool to charge for
|
||
the object. If zero is specified then the default charge for the
|
||
object type is used.
|
||
|
||
Object - Receives a pointer to the newly created object
|
||
|
||
Return Value:
|
||
|
||
Following errors can occur:
|
||
|
||
- invalid object type
|
||
- insufficient memory
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING CapturedObjectName;
|
||
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||
POBJECT_HEADER ObjectHeader;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Allocate a buffer to capture the object creation information.
|
||
//
|
||
|
||
ObjectCreateInfo = ObpAllocateObjectCreateInfoBuffer();
|
||
|
||
if (ObjectCreateInfo == NULL) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Capture the object attributes, quality of service, and object
|
||
// name, if specified. Otherwise, initialize the captured object
|
||
// name, the security quality of service, and the create attributes
|
||
// to default values.
|
||
//
|
||
|
||
Status = ObpCaptureObjectCreateInformation( ObjectType,
|
||
ProbeMode,
|
||
OwnershipMode,
|
||
ObjectAttributes,
|
||
&CapturedObjectName,
|
||
ObjectCreateInfo,
|
||
FALSE );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// If the creation attributes are invalid, then return an error
|
||
// status.
|
||
//
|
||
|
||
if (ObjectType->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Set the paged and nonpaged pool quota charges for the
|
||
// object allocation.
|
||
//
|
||
|
||
if (PagedPoolCharge == 0) {
|
||
|
||
PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
|
||
}
|
||
|
||
if (NonPagedPoolCharge == 0) {
|
||
|
||
NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
|
||
}
|
||
|
||
ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
|
||
ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
|
||
|
||
//
|
||
// Allocate and initialize the object.
|
||
//
|
||
|
||
Status = ObpAllocateObject( ObjectCreateInfo,
|
||
OwnershipMode,
|
||
ObjectType,
|
||
&CapturedObjectName,
|
||
ObjectBodySize,
|
||
&ObjectHeader );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// If a permanent object is being created, then check if
|
||
// the caller has the appropriate privilege.
|
||
//
|
||
|
||
*Object = &ObjectHeader->Body;
|
||
|
||
if (ObjectHeader->Flags & OB_FLAG_PERMANENT_OBJECT) {
|
||
|
||
if (!SeSinglePrivilegeCheck( SeCreatePermanentPrivilege,
|
||
ProbeMode)) {
|
||
|
||
ObpFreeObject(*Object);
|
||
|
||
Status = STATUS_PRIVILEGE_NOT_HELD;
|
||
}
|
||
}
|
||
|
||
#ifdef POOL_TAGGING
|
||
if (ObpTraceEnabled && NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Register the object and push stack information for the
|
||
// first reference
|
||
//
|
||
|
||
ObpRegisterObject( ObjectHeader );
|
||
ObpPushStackInfo( ObjectHeader, TRUE );
|
||
}
|
||
#endif //POOL_TAGGING
|
||
|
||
//
|
||
// Here is the only successful path out of this module but
|
||
// this path can also return privilege not held. In the
|
||
// error case, all the resources have already been freed
|
||
// by ObpFreeObject.
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// An error path, free the create information.
|
||
//
|
||
|
||
ObpReleaseObjectCreateInformation(ObjectCreateInfo);
|
||
|
||
if (CapturedObjectName.Buffer != NULL) {
|
||
|
||
ObpFreeObjectNameBuffer(&CapturedObjectName);
|
||
}
|
||
}
|
||
|
||
//
|
||
// An error path, free object creation information buffer.
|
||
//
|
||
|
||
ObpFreeObjectCreateInfoBuffer(ObjectCreateInfo);
|
||
}
|
||
|
||
//
|
||
// An error path
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ObpCaptureObjectCreateInformation (
|
||
IN POBJECT_TYPE ObjectType OPTIONAL,
|
||
IN KPROCESSOR_MODE ProbeMode,
|
||
IN KPROCESSOR_MODE CreatorMode,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN OUT PUNICODE_STRING CapturedObjectName,
|
||
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
||
IN LOGICAL UseLookaside
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function captures the object creation information and stuff
|
||
it into the input variable ObjectCreateInfo
|
||
|
||
Arguments:
|
||
|
||
ObjectType - Specifies the type of object we expect to capture,
|
||
currently ignored.
|
||
|
||
ProbeMode - Specifies the processor mode for doing our parameter
|
||
probes
|
||
|
||
CreatorMode - Specifies the mode the object is being created for
|
||
|
||
ObjectAttributes - Supplies the object attributes we are trying
|
||
to capture
|
||
|
||
CapturedObjectName - Recieves the name of the object being created
|
||
|
||
ObjectCreateInfo - Receives the create information for the object
|
||
like its root, attributes, and security information
|
||
|
||
UseLookaside - Specifies if we are to allocate the captured name
|
||
buffer from the lookaside list or from straight pool.
|
||
|
||
Return Value:
|
||
|
||
An appropriate status value
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNICODE_STRING ObjectName;
|
||
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||
PSECURITY_QUALITY_OF_SERVICE SecurityQos;
|
||
NTSTATUS Status;
|
||
ULONG Size;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Capture the object attributes, the security quality of service, if
|
||
// specified, and object name, if specified.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
|
||
|
||
try {
|
||
|
||
if (ARGUMENT_PRESENT(ObjectAttributes)) {
|
||
|
||
//
|
||
// Probe the object attributes if necessary.
|
||
//
|
||
|
||
if (ProbeMode != KernelMode) {
|
||
|
||
ProbeForReadSmallStructure( ObjectAttributes,
|
||
sizeof(OBJECT_ATTRIBUTES),
|
||
sizeof(ULONG_PTR) );
|
||
}
|
||
|
||
if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES) ||
|
||
(ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES)) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
goto failureExit;
|
||
}
|
||
|
||
//
|
||
// Capture the object attributes.
|
||
//
|
||
|
||
ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
|
||
ObjectCreateInfo->Attributes = ObjectAttributes->Attributes & OBJ_VALID_ATTRIBUTES;
|
||
//
|
||
// Remove privileged option if passed in from user mode
|
||
//
|
||
if (CreatorMode != KernelMode) {
|
||
ObjectCreateInfo->Attributes &= ~OBJ_KERNEL_HANDLE;
|
||
} else if (ObWatchHandles) {
|
||
if ((ObjectCreateInfo->Attributes&OBJ_KERNEL_HANDLE) == 0 &&
|
||
PsGetCurrentProcess() != PsInitialSystemProcess) {
|
||
DbgBreakPoint ();
|
||
}
|
||
}
|
||
ObjectName = ObjectAttributes->ObjectName;
|
||
SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
|
||
SecurityQos = ObjectAttributes->SecurityQualityOfService;
|
||
|
||
if (ARGUMENT_PRESENT(SecurityDescriptor)) {
|
||
|
||
Status = SeCaptureSecurityDescriptor( SecurityDescriptor,
|
||
ProbeMode,
|
||
PagedPool,
|
||
TRUE,
|
||
&ObjectCreateInfo->SecurityDescriptor );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
KdPrint(( "OB: Failed to capture security descriptor at %08x - Status == %08x\n",
|
||
SecurityDescriptor,
|
||
Status) );
|
||
|
||
//
|
||
// The cleanup routine depends on this being NULL if it isn't
|
||
// allocated. SeCaptureSecurityDescriptor may modify this
|
||
// parameter even if it fails.
|
||
//
|
||
|
||
ObjectCreateInfo->SecurityDescriptor = NULL;
|
||
|
||
goto failureExit;
|
||
}
|
||
|
||
SeComputeQuotaInformationSize( ObjectCreateInfo->SecurityDescriptor,
|
||
&Size );
|
||
|
||
ObjectCreateInfo->SecurityDescriptorCharge = SeComputeSecurityQuota( Size );
|
||
ObjectCreateInfo->ProbeMode = ProbeMode;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(SecurityQos)) {
|
||
|
||
if (ProbeMode != KernelMode) {
|
||
|
||
ProbeForReadSmallStructure( SecurityQos, sizeof(*SecurityQos), sizeof(ULONG));
|
||
}
|
||
|
||
ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
|
||
ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService;
|
||
}
|
||
|
||
} else {
|
||
|
||
ObjectName = NULL;
|
||
}
|
||
|
||
} except (ExSystemExceptionFilter()) {
|
||
|
||
Status = GetExceptionCode();
|
||
|
||
goto failureExit;
|
||
}
|
||
|
||
//
|
||
// If an object name is specified, then capture the object name.
|
||
// Otherwise, initialize the object name descriptor and check for
|
||
// an incorrectly specified root directory.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(ObjectName)) {
|
||
|
||
Status = ObpCaptureObjectName( ProbeMode,
|
||
ObjectName,
|
||
CapturedObjectName,
|
||
UseLookaside );
|
||
|
||
} else {
|
||
|
||
CapturedObjectName->Buffer = NULL;
|
||
CapturedObjectName->Length = 0;
|
||
CapturedObjectName->MaximumLength = 0;
|
||
|
||
if (ARGUMENT_PRESENT(ObjectCreateInfo->RootDirectory)) {
|
||
|
||
Status = STATUS_OBJECT_NAME_INVALID;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the completion status is not successful, and a security quality
|
||
// of service parameter was specified, then free the security quality
|
||
// of service memory.
|
||
//
|
||
|
||
failureExit:
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
ObpReleaseObjectCreateInformation(ObjectCreateInfo);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ObpCaptureObjectName (
|
||
IN KPROCESSOR_MODE ProbeMode,
|
||
IN PUNICODE_STRING ObjectName,
|
||
IN OUT PUNICODE_STRING CapturedObjectName,
|
||
IN LOGICAL UseLookaside
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function captures the object name but first verifies that
|
||
it is at least properly sized.
|
||
|
||
Arguments:
|
||
|
||
ProbeMode - Supplies the processor mode to use when probing
|
||
the object name
|
||
|
||
ObjectName - Supplies the caller's version of the object name
|
||
|
||
CapturedObjectName - Receives the captured verified version
|
||
of the object name
|
||
|
||
UseLookaside - Indicates if the captured name buffer should be
|
||
allocated from the lookaside list or from straight pool
|
||
|
||
Return Value:
|
||
|
||
An appropriate status value
|
||
|
||
--*/
|
||
|
||
{
|
||
PWCH FreeBuffer;
|
||
UNICODE_STRING InputObjectName;
|
||
ULONG Length;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize the object name descriptor and capture the specified name
|
||
// string.
|
||
//
|
||
|
||
CapturedObjectName->Buffer = NULL;
|
||
CapturedObjectName->Length = 0;
|
||
CapturedObjectName->MaximumLength = 0;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
try {
|
||
|
||
//
|
||
// Probe and capture the name string descriptor and probe the
|
||
// name string, if necessary.
|
||
//
|
||
|
||
FreeBuffer = NULL;
|
||
|
||
if (ProbeMode != KernelMode) {
|
||
|
||
InputObjectName = ProbeAndReadUnicodeString(ObjectName);
|
||
|
||
ProbeForRead( InputObjectName.Buffer,
|
||
InputObjectName.Length,
|
||
sizeof(WCHAR) );
|
||
|
||
} else {
|
||
|
||
InputObjectName = *ObjectName;
|
||
}
|
||
|
||
//
|
||
// If the length of the string is not zero, then capture the string.
|
||
//
|
||
|
||
if (InputObjectName.Length != 0) {
|
||
|
||
//
|
||
// If the length of the string is not an even multiple of the
|
||
// size of a UNICODE character or cannot be zero terminated,
|
||
// then return an error.
|
||
//
|
||
|
||
Length = InputObjectName.Length;
|
||
|
||
if (((Length & (sizeof(WCHAR) - 1)) != 0) ||
|
||
(Length == (MAXUSHORT - sizeof(WCHAR) + 1))) {
|
||
|
||
Status = STATUS_OBJECT_NAME_INVALID;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Allocate a buffer for the specified name string.
|
||
//
|
||
// N.B. The name buffer allocation routine adds one
|
||
// UNICODE character to the length and initializes
|
||
// the string descriptor.
|
||
//
|
||
|
||
FreeBuffer = ObpAllocateObjectNameBuffer( Length,
|
||
UseLookaside,
|
||
CapturedObjectName );
|
||
|
||
if (FreeBuffer == NULL) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Copy the specified name string to the destination
|
||
// buffer.
|
||
//
|
||
|
||
RtlCopyMemory(FreeBuffer, InputObjectName.Buffer, Length);
|
||
|
||
//
|
||
// Zero terminate the name string and initialize the
|
||
// string descriptor.
|
||
//
|
||
|
||
FreeBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
} except(ExSystemExceptionFilter()) {
|
||
|
||
Status = GetExceptionCode();
|
||
|
||
if (FreeBuffer != NULL) {
|
||
|
||
ExFreePool(FreeBuffer);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
PWCHAR
|
||
ObpAllocateObjectNameBuffer (
|
||
IN ULONG Length,
|
||
IN LOGICAL UseLookaside,
|
||
IN OUT PUNICODE_STRING ObjectName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function allocates an object name buffer.
|
||
|
||
N.B. This function is nonpageable.
|
||
|
||
Arguments:
|
||
|
||
Length - Supplies the length of the required buffer in bytes.
|
||
|
||
UseLookaside - Supplies a logical variable that determines whether an
|
||
attempt is made to allocate the name buffer from the lookaside list.
|
||
|
||
ObjectName - Supplies a pointer to a name buffer string descriptor.
|
||
|
||
Return Value:
|
||
|
||
If the allocation is successful, then name buffer string descriptor
|
||
is initialized and the address of the name buffer is returned as the
|
||
function value. Otherwise, a value of NULL is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Buffer;
|
||
ULONG Maximum;
|
||
KIRQL OldIrql;
|
||
PKPRCB Prcb;
|
||
|
||
//
|
||
// If allocation from the lookaside lists is specified and the buffer
|
||
// size is less than the size of lookaside list entries, then attempt
|
||
// to allocate the name buffer from the lookaside lists. Otherwise,
|
||
// attempt to allocate the name buffer from nonpaged pool.
|
||
//
|
||
|
||
Maximum = Length + sizeof(WCHAR);
|
||
|
||
if ((UseLookaside == FALSE) || (Maximum > OBJECT_NAME_BUFFER_SIZE)) {
|
||
|
||
//
|
||
// Attempt to allocate the buffer from nonpaged pool.
|
||
//
|
||
|
||
Buffer = ExAllocatePoolWithTag( OB_NAMESPACE_POOL_TYPE , Maximum, 'mNbO' );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Attempt to allocate the name buffer from the lookaside list. If
|
||
// the allocation attempt fails, then attempt to allocate the name
|
||
// buffer from pool.
|
||
//
|
||
|
||
Maximum = OBJECT_NAME_BUFFER_SIZE;
|
||
Buffer = ExAllocateFromPPLookasideList(LookasideNameBufferList);
|
||
}
|
||
|
||
//
|
||
// Initialize the string descriptor and return the buffer address.
|
||
//
|
||
|
||
ObjectName->Length = (USHORT)Length;
|
||
ObjectName->MaximumLength = (USHORT)Maximum;
|
||
ObjectName->Buffer = Buffer;
|
||
|
||
return (PWCHAR)Buffer;
|
||
}
|
||
|
||
|
||
VOID
|
||
FASTCALL
|
||
ObpFreeObjectNameBuffer (
|
||
OUT PUNICODE_STRING ObjectName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function frees an object name buffer.
|
||
|
||
N.B. This function is nonpageable.
|
||
|
||
Arguments:
|
||
|
||
ObjectName - Supplies a pointer to a name buffer string descriptor.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Buffer;
|
||
KIRQL OldIrql;
|
||
PKPRCB Prcb;
|
||
|
||
//
|
||
// If the size of the buffer is not equal to the size of lookaside list
|
||
// entries, then free the buffer to pool. Otherwise, free the buffer to
|
||
// the lookaside list.
|
||
//
|
||
|
||
Buffer = ObjectName->Buffer;
|
||
|
||
if (ObjectName->MaximumLength != OBJECT_NAME_BUFFER_SIZE) {
|
||
ExFreePool(Buffer);
|
||
|
||
} else {
|
||
ExFreeToPPLookasideList(LookasideNameBufferList, Buffer);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
NTKERNELAPI
|
||
VOID
|
||
ObDeleteCapturedInsertInfo (
|
||
IN PVOID Object
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function frees the creation information that could be pointed at
|
||
by the object header.
|
||
|
||
Arguments:
|
||
|
||
Object - Supplies the object being modified
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
POBJECT_HEADER ObjectHeader;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get the address of the object header and free the object create
|
||
// information object if the object is being created.
|
||
//
|
||
|
||
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
|
||
|
||
if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {
|
||
|
||
if (ObjectHeader->ObjectCreateInfo != NULL) {
|
||
|
||
ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);
|
||
|
||
ObjectHeader->ObjectCreateInfo = NULL;
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ObpAllocateObject (
|
||
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
||
IN KPROCESSOR_MODE OwnershipMode,
|
||
IN POBJECT_TYPE ObjectType OPTIONAL,
|
||
IN PUNICODE_STRING ObjectName,
|
||
IN ULONG ObjectBodySize,
|
||
OUT POBJECT_HEADER *ReturnedObjectHeader
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates a new object including the object header
|
||
and body from pool and fill in the appropriate fields.
|
||
|
||
Arguments:
|
||
|
||
ObjectCreateInfo - Supplies the create information for the new object
|
||
|
||
OwnershipMode - Supplies the processor mode of who is going to own
|
||
the object
|
||
|
||
ObjectType - Optionally supplies the object type of the object being
|
||
created. If the object create info not null then this field must
|
||
be supplied.
|
||
|
||
ObjectName - Supplies the name of the object being created
|
||
|
||
ObjectBodySize - Specifies the size, in bytes, of the body of the object
|
||
being created
|
||
|
||
ReturnedObjectHeader - Receives a pointer to the object header for the
|
||
newly created objet.
|
||
|
||
Return Value:
|
||
|
||
An appropriate status value.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG HeaderSize;
|
||
POBJECT_HEADER ObjectHeader;
|
||
NTSTATUS Status;
|
||
PVOID ZoneSegment;
|
||
ULONG QuotaInfoSize;
|
||
ULONG HandleInfoSize;
|
||
ULONG NameInfoSize;
|
||
ULONG CreatorInfoSize;
|
||
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
|
||
POBJECT_HEADER_HANDLE_INFO HandleInfo;
|
||
POBJECT_HEADER_NAME_INFO NameInfo;
|
||
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
||
POOL_TYPE PoolType;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if DBG
|
||
ObpObjectsCreated += 1;
|
||
#endif // DBG
|
||
|
||
//
|
||
// Compute the sizes of the optional object header components.
|
||
//
|
||
|
||
if (ObjectCreateInfo == NULL) {
|
||
|
||
QuotaInfoSize = 0;
|
||
HandleInfoSize = 0;
|
||
NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO );
|
||
CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO );
|
||
|
||
} else {
|
||
|
||
//
|
||
// The caller specified some additional object create info
|
||
//
|
||
// First check to see if we need to set the quota
|
||
//
|
||
|
||
if (((ObjectCreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge ||
|
||
ObjectCreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge ||
|
||
ObjectCreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA) &&
|
||
PsGetCurrentProcess() != PsInitialSystemProcess) ||
|
||
(ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {
|
||
|
||
QuotaInfoSize = sizeof( OBJECT_HEADER_QUOTA_INFO );
|
||
#if DBG
|
||
ObpObjectsWithPoolQuota += 1;
|
||
#endif // DBG
|
||
|
||
} else {
|
||
|
||
QuotaInfoSize = 0;
|
||
}
|
||
|
||
//
|
||
// Check if we are to allocate space to maintain handle counts
|
||
//
|
||
|
||
if (ObjectType->TypeInfo.MaintainHandleCount) {
|
||
|
||
HandleInfoSize = sizeof( OBJECT_HEADER_HANDLE_INFO );
|
||
#if DBG
|
||
ObpObjectsWithHandleDB += 1;
|
||
#endif // DBG
|
||
|
||
} else {
|
||
|
||
HandleInfoSize = 0;
|
||
}
|
||
|
||
//
|
||
// Check if we are to allocate space for the name
|
||
//
|
||
|
||
if (ObjectName->Buffer != NULL) {
|
||
|
||
NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO );
|
||
#if DBG
|
||
ObpObjectsWithName += 1;
|
||
#endif // DBG
|
||
|
||
} else {
|
||
|
||
NameInfoSize = 0;
|
||
}
|
||
|
||
//
|
||
// Finally check if we are to maintain the creator info
|
||
//
|
||
|
||
if (ObjectType->TypeInfo.MaintainTypeList) {
|
||
|
||
CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO );
|
||
#if DBG
|
||
ObpObjectsWithCreatorInfo += 1;
|
||
#endif // DBG
|
||
|
||
} else {
|
||
|
||
CreatorInfoSize = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now compute the total header size
|
||
//
|
||
|
||
HeaderSize = QuotaInfoSize +
|
||
HandleInfoSize +
|
||
NameInfoSize +
|
||
CreatorInfoSize +
|
||
FIELD_OFFSET( OBJECT_HEADER, Body );
|
||
|
||
//
|
||
// Allocate and initialize the object.
|
||
//
|
||
// If the object type is not specified or specifies nonpaged pool,
|
||
// then allocate the object from nonpaged pool.
|
||
// Otherwise, allocate the object from paged pool.
|
||
//
|
||
|
||
if ((ObjectType == NULL) || (ObjectType->TypeInfo.PoolType == NonPagedPool)) {
|
||
|
||
PoolType = NonPagedPool;
|
||
|
||
} else {
|
||
|
||
PoolType = PagedPool;
|
||
}
|
||
|
||
ObjectHeader = ExAllocatePoolWithTag( PoolType,
|
||
HeaderSize + ObjectBodySize,
|
||
(ObjectType == NULL ? 'TjbO' : ObjectType->Key) |
|
||
PROTECTED_POOL );
|
||
|
||
if (ObjectHeader == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Now based on if we are to put in the quota, handle, name, or creator info we
|
||
// will do the extra work. This order is very important because we rely on
|
||
// it to free the object.
|
||
//
|
||
|
||
if (QuotaInfoSize != 0) {
|
||
|
||
QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)ObjectHeader;
|
||
QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
|
||
QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
|
||
QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
|
||
QuotaInfo->ExclusiveProcess = NULL;
|
||
ObjectHeader = (POBJECT_HEADER)(QuotaInfo + 1);
|
||
}
|
||
|
||
if (HandleInfoSize != 0) {
|
||
|
||
HandleInfo = (POBJECT_HEADER_HANDLE_INFO)ObjectHeader;
|
||
HandleInfo->SingleEntry.HandleCount = 0;
|
||
ObjectHeader = (POBJECT_HEADER)(HandleInfo + 1);
|
||
}
|
||
|
||
if (NameInfoSize != 0) {
|
||
|
||
NameInfo = (POBJECT_HEADER_NAME_INFO)ObjectHeader;
|
||
NameInfo->Name = *ObjectName;
|
||
NameInfo->Directory = NULL;
|
||
NameInfo->QueryReferences = 1;
|
||
ObjectHeader = (POBJECT_HEADER)(NameInfo + 1);
|
||
}
|
||
|
||
if (CreatorInfoSize != 0) {
|
||
|
||
CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)ObjectHeader;
|
||
CreatorInfo->CreatorBackTraceIndex = 0;
|
||
CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcess()->UniqueProcessId;
|
||
InitializeListHead( &CreatorInfo->TypeList );
|
||
|
||
PERFINFO_ADD_OBJECT_TO_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectType);
|
||
|
||
ObjectHeader = (POBJECT_HEADER)(CreatorInfo + 1);
|
||
}
|
||
|
||
//
|
||
// Compute the proper offsets based on what we have
|
||
//
|
||
|
||
if (QuotaInfoSize != 0) {
|
||
|
||
ObjectHeader->QuotaInfoOffset = (UCHAR)(QuotaInfoSize + HandleInfoSize + NameInfoSize + CreatorInfoSize);
|
||
|
||
} else {
|
||
|
||
ObjectHeader->QuotaInfoOffset = 0;
|
||
}
|
||
|
||
if (HandleInfoSize != 0) {
|
||
|
||
ObjectHeader->HandleInfoOffset = (UCHAR)(HandleInfoSize + NameInfoSize + CreatorInfoSize);
|
||
|
||
} else {
|
||
|
||
ObjectHeader->HandleInfoOffset = 0;
|
||
}
|
||
|
||
if (NameInfoSize != 0) {
|
||
|
||
ObjectHeader->NameInfoOffset = (UCHAR)(NameInfoSize + CreatorInfoSize);
|
||
|
||
} else {
|
||
|
||
ObjectHeader->NameInfoOffset = 0;
|
||
}
|
||
|
||
//
|
||
// Say that this is a new object, and conditionally set the other flags
|
||
//
|
||
|
||
ObjectHeader->Flags = OB_FLAG_NEW_OBJECT;
|
||
|
||
if (CreatorInfoSize != 0) {
|
||
|
||
ObjectHeader->Flags |= OB_FLAG_CREATOR_INFO;
|
||
}
|
||
|
||
if (HandleInfoSize != 0) {
|
||
|
||
ObjectHeader->Flags |= OB_FLAG_SINGLE_HANDLE_ENTRY;
|
||
}
|
||
|
||
//
|
||
// Set the counters and its type
|
||
//
|
||
|
||
ObjectHeader->PointerCount = 1;
|
||
ObjectHeader->HandleCount = 0;
|
||
ObjectHeader->Type = ObjectType;
|
||
|
||
//
|
||
// Initialize the object header.
|
||
//
|
||
// N.B. The initialization of the object header is done field by
|
||
// field rather than zeroing the memory and then initializing
|
||
// the pertinent fields.
|
||
//
|
||
// N.B. It is assumed that the caller will initialize the object
|
||
// attributes, object ownership, and parse context.
|
||
//
|
||
|
||
if (OwnershipMode == KernelMode) {
|
||
|
||
ObjectHeader->Flags |= OB_FLAG_KERNEL_OBJECT;
|
||
}
|
||
|
||
if (ObjectCreateInfo != NULL &&
|
||
ObjectCreateInfo->Attributes & OBJ_PERMANENT ) {
|
||
|
||
ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
|
||
}
|
||
|
||
if ((ObjectCreateInfo != NULL) &&
|
||
(ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {
|
||
|
||
ObjectHeader->Flags |= OB_FLAG_EXCLUSIVE_OBJECT;
|
||
}
|
||
|
||
ObjectHeader->ObjectCreateInfo = ObjectCreateInfo;
|
||
ObjectHeader->SecurityDescriptor = NULL;
|
||
|
||
if (ObjectType != NULL) {
|
||
|
||
ObjectType->TotalNumberOfObjects += 1;
|
||
|
||
if (ObjectType->TotalNumberOfObjects > ObjectType->HighWaterNumberOfObjects) {
|
||
|
||
ObjectType->HighWaterNumberOfObjects = ObjectType->TotalNumberOfObjects;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// On a checked build echo out allocs
|
||
//
|
||
|
||
if (ObpShowAllocAndFree) {
|
||
|
||
DbgPrint( "OB: Alloc %lx (%lx) %04lu", ObjectHeader, ObjectHeader, ObjectBodySize );
|
||
|
||
if (ObjectType) {
|
||
|
||
DbgPrint(" - %wZ\n", &ObjectType->Name );
|
||
|
||
} else {
|
||
|
||
DbgPrint(" - Type\n" );
|
||
}
|
||
}
|
||
#endif
|
||
|
||
*ReturnedObjectHeader = ObjectHeader;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
FASTCALL
|
||
ObpFreeObject (
|
||
IN PVOID Object
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine undoes ObpAllocateObject. It returns the object back to free pool.
|
||
|
||
Arguments:
|
||
|
||
Object - Supplies a pointer to the body of the object being freed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
POBJECT_HEADER ObjectHeader;
|
||
POBJECT_TYPE ObjectType;
|
||
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
|
||
POBJECT_HEADER_HANDLE_INFO HandleInfo;
|
||
POBJECT_HEADER_NAME_INFO NameInfo;
|
||
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
||
PVOID FreeBuffer;
|
||
ULONG NonPagedPoolCharge;
|
||
ULONG PagedPoolCharge;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get the address of the object header.
|
||
//
|
||
|
||
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
|
||
ObjectType = ObjectHeader->Type;
|
||
|
||
//
|
||
// Now from the header determine the start of the allocation. We need
|
||
// to backup based on what precedes the header. The order is very
|
||
// important and must be the inverse of that used by ObpAllocateObject
|
||
//
|
||
|
||
FreeBuffer = ObjectHeader;
|
||
|
||
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );
|
||
|
||
if (CreatorInfo != NULL) {
|
||
|
||
FreeBuffer = CreatorInfo;
|
||
}
|
||
|
||
NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
|
||
|
||
if (NameInfo != NULL) {
|
||
|
||
FreeBuffer = NameInfo;
|
||
}
|
||
|
||
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader );
|
||
|
||
if (HandleInfo != NULL) {
|
||
|
||
FreeBuffer = HandleInfo;
|
||
}
|
||
|
||
QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
|
||
|
||
if (QuotaInfo != NULL) {
|
||
|
||
FreeBuffer = QuotaInfo;
|
||
}
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// On a checked build echo out frees
|
||
//
|
||
|
||
if (ObpShowAllocAndFree) {
|
||
|
||
DbgPrint( "OB: Free %lx (%lx) - Type: %wZ\n", ObjectHeader, ObjectHeader, &ObjectType->Name );
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Decrement the number of objects of this type
|
||
//
|
||
|
||
ObjectType->TotalNumberOfObjects -= 1;
|
||
|
||
//
|
||
// Check where we were in the object initialization phase. This
|
||
// flag really only tests if we have charged quota for this object.
|
||
// This is because the object create info and the quota block charged
|
||
// are unioned together.
|
||
//
|
||
|
||
if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {
|
||
|
||
if (ObjectHeader->ObjectCreateInfo != NULL) {
|
||
|
||
ObpFreeObjectCreateInformation( ObjectHeader->ObjectCreateInfo );
|
||
|
||
ObjectHeader->ObjectCreateInfo = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
if (ObjectHeader->QuotaBlockCharged != NULL) {
|
||
|
||
if (QuotaInfo != NULL) {
|
||
|
||
PagedPoolCharge = QuotaInfo->PagedPoolCharge +
|
||
QuotaInfo->SecurityDescriptorCharge;
|
||
|
||
NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;
|
||
|
||
} else {
|
||
|
||
PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
|
||
|
||
if (ObjectHeader->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA ) {
|
||
|
||
PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
|
||
}
|
||
|
||
NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
|
||
}
|
||
|
||
PsReturnSharedPoolQuota( ObjectHeader->QuotaBlockCharged,
|
||
PagedPoolCharge,
|
||
NonPagedPoolCharge );
|
||
|
||
ObjectHeader->QuotaBlockCharged = NULL;
|
||
}
|
||
}
|
||
|
||
if ((HandleInfo != NULL) &&
|
||
((ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) == 0)) {
|
||
|
||
//
|
||
// If a handle database has been allocated, then free the memory.
|
||
//
|
||
|
||
ExFreePool( HandleInfo->HandleCountDataBase );
|
||
|
||
HandleInfo->HandleCountDataBase = NULL;
|
||
}
|
||
|
||
//
|
||
// If a name string buffer has been allocated, then free the memory.
|
||
//
|
||
|
||
if (NameInfo != NULL && NameInfo->Name.Buffer != NULL) {
|
||
|
||
ExFreePool( NameInfo->Name.Buffer );
|
||
|
||
NameInfo->Name.Buffer = NULL;
|
||
}
|
||
|
||
PERFINFO_REMOVE_OBJECT_FROM_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectHeader);
|
||
|
||
//
|
||
// Trash type field so we don't get far if we attempt to
|
||
// use a stale object pointer to this object.
|
||
//
|
||
// Sundown Note: trash it by zero-extended it.
|
||
// sign-extension will create a valid kernel address.
|
||
|
||
|
||
ObjectHeader->Type = UIntToPtr(0xBAD0B0B0);
|
||
ExFreePoolWithTag( FreeBuffer,
|
||
(ObjectType == NULL ? 'TjbO' : ObjectType->Key) |
|
||
PROTECTED_POOL );
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
FASTCALL
|
||
ObFreeObjectCreateInfoBuffer (
|
||
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function frees a create information buffer. Called from IO component
|
||
|
||
N.B. This function is nonpageable.
|
||
|
||
Arguments:
|
||
|
||
ObjectCreateInfo - Supplies a pointer to a create information buffer.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ObpFreeObjectCreateInfoBuffer( ObjectCreateInfo );
|
||
|
||
return;
|
||
}
|