- Set an invalid pointer as the object header's type when freeing it, to detect invalid usage.

- Optimize type mutex acquisition in ObpDeleteObject. Also optimize freeing of the unicode_String containing the name. Also add callout checks/protection during the security and delete procedure callouts.
- Acquire object type mutex during modification of the OB_FLAG_PERMANENT flag in ObpSetPermanentObject.
- Initialize default QueryReferences field to 1 during object allocation.
- Support undocumented 0x10000 object attribute flag used in Windows 2003 SP1 and higher to protect objects from user-mode access (such as PhysicalMemory).
- Use InterlockedIncrements for ObjectType accounting outside the type lock.
- Clear the lookup context's object pointer for future use.

svn path=/trunk/; revision=25369
This commit is contained in:
Alex Ionescu 2007-01-08 07:51:07 +00:00
parent 5626181735
commit d107f7d0f4

View file

@ -107,9 +107,6 @@ ObpDeallocateObject(IN PVOID Object)
/* Add the SD charge too */ /* Add the SD charge too */
if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048; if (Header->Flags & OB_FLAG_SECURITY) PagedPoolCharge += 2048;
} }
/* FIXME: Should be returning quota */
DPRINT("Quotas: %lx %lx\n", PagedPoolCharge, NonPagedPoolCharge);
} }
} }
@ -129,6 +126,9 @@ ObpDeallocateObject(IN PVOID Object)
NameInfo->Name.Buffer = NULL; NameInfo->Name.Buffer = NULL;
} }
/* Catch invalid access */
Header->Type = (POBJECT_TYPE)0xBAADB0B0;
/* Free the object using the same allocation tag */ /* Free the object using the same allocation tag */
ExFreePoolWithTag(HeaderLocation, ObjectType->Key); ExFreePoolWithTag(HeaderLocation, ObjectType->Key);
} }
@ -142,6 +142,7 @@ ObpDeleteObject(IN PVOID Object,
POBJECT_TYPE ObjectType; POBJECT_TYPE ObjectType;
POBJECT_HEADER_NAME_INFO NameInfo; POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_HEADER_CREATOR_INFO CreatorInfo; POBJECT_HEADER_CREATOR_INFO CreatorInfo;
KIRQL CalloutIrql;
PAGED_CODE(); PAGED_CODE();
/* Get the header and type */ /* Get the header and type */
@ -152,33 +153,32 @@ ObpDeleteObject(IN PVOID Object,
NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header); NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header); CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
/* Lock the object type */
ObpEnterObjectTypeMutex(ObjectType);
/* Check if the object is on a type list */ /* Check if the object is on a type list */
if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList))) if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
{ {
/* Lock the object type */
ObpEnterObjectTypeMutex(ObjectType);
/* Remove the object from the type list */ /* Remove the object from the type list */
RemoveEntryList(&CreatorInfo->TypeList); RemoveEntryList(&CreatorInfo->TypeList);
}
/* Release the lock */ /* Release the lock */
ObpLeaveObjectTypeMutex(ObjectType); ObpLeaveObjectTypeMutex(ObjectType);
}
/* Check if we have a name */ /* Check if we have a name */
if ((NameInfo) && (NameInfo->Name.Buffer)) if ((NameInfo) && (NameInfo->Name.Buffer))
{ {
/* Free it */ /* Free it */
ExFreePool(NameInfo->Name.Buffer); ExFreePool(NameInfo->Name.Buffer);
RtlInitEmptyUnicodeString(&NameInfo->Name, NULL, 0);
/* Clean up the string so we don't try this again */
RtlInitUnicodeString(&NameInfo->Name, NULL);
} }
/* Check if we have a security descriptor */ /* Check if we have a security descriptor */
if (Header->SecurityDescriptor) if (Header->SecurityDescriptor)
{ {
/* Call the security procedure to delete it */ /* Call the security procedure to delete it */
ObpCalloutStart(&CalloutIrql);
ObjectType->TypeInfo.SecurityProcedure(Object, ObjectType->TypeInfo.SecurityProcedure(Object,
DeleteSecurityDescriptor, DeleteSecurityDescriptor,
0, 0,
@ -187,13 +187,16 @@ ObpDeleteObject(IN PVOID Object,
&Header->SecurityDescriptor, &Header->SecurityDescriptor,
0, 0,
NULL); NULL);
ObpCalloutEnd(CalloutIrql, "Security", ObjectType, Object);
} }
/* Check if we have a delete procedure */ /* Check if we have a delete procedure */
if (ObjectType->TypeInfo.DeleteProcedure) if (ObjectType->TypeInfo.DeleteProcedure)
{ {
/* Call it */ /* Call it */
ObpCalloutStart(&CalloutIrql);
ObjectType->TypeInfo.DeleteProcedure(Object); ObjectType->TypeInfo.DeleteProcedure(Object);
ObpCalloutEnd(CalloutIrql, "Delete", ObjectType, Object);
} }
/* Now de-allocate all object members */ /* Now de-allocate all object members */
@ -256,16 +259,27 @@ ObpSetPermanentObject(IN PVOID ObjectBody,
/* Get the header */ /* Get the header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody); ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
/* Acquire object type lock */
ObpEnterObjectTypeMutex(ObjectHeader->Type);
/* Check what we're doing to it */
if (Permanent) if (Permanent)
{ {
/* Set it to permanent */ /* Set it to permanent */
ObjectHeader->Flags |= OB_FLAG_PERMANENT; ObjectHeader->Flags |= OB_FLAG_PERMANENT;
/* Release the lock */
ObpLeaveObjectTypeMutex(ObjectHeader->Type);
} }
else else
{ {
/* Remove the flag */ /* Remove the flag */
ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; ObjectHeader->Flags &= ~OB_FLAG_PERMANENT;
/* Release the lock */
ObpLeaveObjectTypeMutex(ObjectHeader->Type);
/* Check if we should delete the object now */ /* Check if we should delete the object now */
ObpDeleteNameCheck(ObjectBody); ObpDeleteNameCheck(ObjectBody);
} }
@ -623,9 +637,10 @@ ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag); Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
if (!Header) return STATUS_INSUFFICIENT_RESOURCES; if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
/* Initialize quota info */ /* Check if we have a quota header */
if (QuotaSize) if (QuotaSize)
{ {
/* Initialize quota info */
QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header; QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)Header;
QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge; QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge; QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
@ -634,26 +649,41 @@ ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
Header = (POBJECT_HEADER)(QuotaInfo + 1); Header = (POBJECT_HEADER)(QuotaInfo + 1);
} }
/* Initialize Handle Info */ /* Check if we have a handle database header */
if (HandleSize) if (HandleSize)
{ {
/* Initialize Handle Info */
HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
HandleInfo->SingleEntry.HandleCount = 0; HandleInfo->SingleEntry.HandleCount = 0;
Header = (POBJECT_HEADER)(HandleInfo + 1); Header = (POBJECT_HEADER)(HandleInfo + 1);
} }
/* Initialize the Object Name Info */ /* Check if we have a name header */
if (NameSize) if (NameSize)
{ {
/* Initialize the Object Name Info */
NameInfo = (POBJECT_HEADER_NAME_INFO)Header; NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
NameInfo->Name = *ObjectName; NameInfo->Name = *ObjectName;
NameInfo->Directory = NULL; NameInfo->Directory = NULL;
NameInfo->QueryReferences = 1;
/* Check if this is a call with the special protection flag */
if ((PreviousMode == KernelMode) &&
(ObjectCreateInfo) &&
(ObjectCreateInfo->Attributes & 0x10000))
{
/* Set flag which will make the object protected from user-mode */
NameInfo->QueryReferences |= 0x40000000;
}
/* Set the header pointer */
Header = (POBJECT_HEADER)(NameInfo + 1); Header = (POBJECT_HEADER)(NameInfo + 1);
} }
/* Initialize Creator Info */ /* Check if we have a creator header */
if (CreatorSize) if (CreatorSize)
{ {
/* Initialize Creator Info */
CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
CreatorInfo->CreatorBackTraceIndex = 0; CreatorInfo->CreatorBackTraceIndex = 0;
CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId();
@ -739,7 +769,7 @@ ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
if (ObjectType) if (ObjectType)
{ {
/* Increase the number of objects of this type */ /* Increase the number of objects of this type */
ObjectType->TotalNumberOfObjects++; InterlockedIncrement(&ObjectType->TotalNumberOfObjects);
/* Update the high water */ /* Update the high water */
ObjectType->HighWaterNumberOfObjects = max(ObjectType-> ObjectType->HighWaterNumberOfObjects = max(ObjectType->
@ -774,8 +804,6 @@ ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL,
POBJECT_CREATE_INFORMATION ObjectCreateInfo; POBJECT_CREATE_INFORMATION ObjectCreateInfo;
UNICODE_STRING ObjectName; UNICODE_STRING ObjectName;
POBJECT_HEADER Header; POBJECT_HEADER Header;
DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
Type, ObjectAttributes, Object);
/* Allocate a capture buffer */ /* Allocate a capture buffer */
ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList); ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList);
@ -898,6 +926,8 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID; if (*p++ == OBJ_NAME_PATH_SEPARATOR) return STATUS_OBJECT_NAME_INVALID;
} }
Context.Object = NULL;
/* Check if we've already created the directory of types */ /* Check if we've already created the directory of types */
if (ObpTypeDirectoryObject) if (ObpTypeDirectoryObject)
{ {
@ -911,6 +941,7 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
&Context)) &Context))
{ {
/* We have already created it, so fail */ /* We have already created it, so fail */
Context.Object = NULL;
return STATUS_OBJECT_NAME_COLLISION; return STATUS_OBJECT_NAME_COLLISION;
} }
} }
@ -922,6 +953,7 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
if (!ObjectName.Buffer) if (!ObjectName.Buffer)
{ {
/* Out of memory, fail */ /* Out of memory, fail */
Context.Object = NULL;
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -938,6 +970,8 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
(POBJECT_HEADER*)&Header); (POBJECT_HEADER*)&Header);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
Context.Object = NULL;
/* Free the name and fail */ /* Free the name and fail */
ExFreePool(ObjectName.Buffer); ExFreePool(ObjectName.Buffer);
return Status; return Status;
@ -1067,12 +1101,15 @@ ObCreateObjectType(IN PUNICODE_STRING TypeName,
ObReferenceObject(ObpTypeDirectoryObject); ObReferenceObject(ObpTypeDirectoryObject);
} }
Context.Object = NULL;
/* Return the object type and success */ /* Return the object type and success */
*ObjectType = LocalObjectType; *ObjectType = LocalObjectType;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* If we got here, then we failed */ /* If we got here, then we failed */
Context.Object = NULL;
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
@ -1094,6 +1131,8 @@ VOID
NTAPI NTAPI
ObMakeTemporaryObject(IN PVOID ObjectBody) ObMakeTemporaryObject(IN PVOID ObjectBody)
{ {
PAGED_CODE();
/* Call the internal API */ /* Call the internal API */
ObpSetPermanentObject(ObjectBody, FALSE); ObpSetPermanentObject(ObjectBody, FALSE);
} }