From 6829abde131e61a775ba9a593e3f2a6ec9317aaf Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 9 Jan 2007 07:28:40 +0000 Subject: [PATCH] - Add internal macros for acquiring the object directory pushlock during lookup (not yet used). - Add internal macros for incrementing/decrementing query references, and use them where appropriate. Do not yet support the path for an object which is currently being defer deleted. - Add internal macros for cleaning up a directory lookup (not yet used and needs renaming/cleanup), initializing a directory lookup (not yet used). - Don't call security callback in ObpDeleteNameCheck. Make sure permanent flag is still cleared after acquiring type lock. Add special call for symboilc links. Add commented out calls to lock the object directory. svn path=/trunk/; revision=25392 --- reactos/ntoskrnl/include/internal/ob_x.h | 191 +++++++++++++++++++++++ reactos/ntoskrnl/ob/obhandle.c | 29 +++- reactos/ntoskrnl/ob/obname.c | 98 ++++++++---- 3 files changed, 283 insertions(+), 35 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/ob_x.h b/reactos/ntoskrnl/include/internal/ob_x.h index 12cb5e9735b..cf7ce2548a8 100644 --- a/reactos/ntoskrnl/include/internal/ob_x.h +++ b/reactos/ntoskrnl/include/internal/ob_x.h @@ -6,6 +6,8 @@ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ +#include "ex.h" + #if DBG VOID FORCEINLINE @@ -53,6 +55,193 @@ ObpCalloutEnd(IN KIRQL CalloutIrql, } #endif +VOID +FORCEINLINE +_ObpAcquireDirectoryLockShared(IN POBJECT_DIRECTORY Directory, + IN POBP_LOOKUP_CONTEXT Context) +{ + /* It's not, set lock flag */ + Context->LockStateSignature = 0xBBBB1234; + + /* Lock it */ + KeEnterCriticalRegion(); + ExAcquirePushLockShared(&Directory->Lock); + + /* Update lock flag */ + Context->LockStateSignature = 0xDDDD1234; +} + +VOID +FORCEINLINE +_ObpAcquireDirectoryLockExclusive(IN POBJECT_DIRECTORY Directory, + IN POBP_LOOKUP_CONTEXT Context) +{ + /* Update lock flag */ + Context->LockStateSignature = 0xAAAA1234; + + /* Lock it */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&Directory->Lock); +} + +VOID +FORCEINLINE +_ObpReleaseDirectoryLock(IN POBJECT_DIRECTORY Directory, + IN POBP_LOOKUP_CONTEXT Context) +{ + /* Release the lock */ + ExReleasePushLock(&Directory->Lock); + Context->LockStateSignature = 0xEEEE1234; + KeLeaveCriticalRegion(); +} + +ULONG +FORCEINLINE +ObpIncrementQueryReference(IN POBJECT_HEADER ObjectHeader, + IN POBJECT_HEADER_NAME_INFO ObjectNameInfo) +{ + ULONG NewValue, References; + + /* Get the number of references */ + NewValue = ObjectNameInfo->QueryReferences; + while ((NewValue != 0) && (References = NewValue)) + { + /* Increment the number of references */ + if (InterlockedCompareExchange(&ObjectNameInfo->QueryReferences, + NewValue + 1, + NewValue) == References) + { + /* Check if the object is to be deferred deleted */ + if (ObjectHeader->Flags & OB_FLAG_DEFER_DELETE) + { + /* FIXME: Unhandled*/ + DbgPrint("OB: Unhandled path\n"); + KEBUGCHECK(0); + } + + /* Done looping */ + NewValue = ObjectNameInfo->QueryReferences; + break; + } + } + + /* Return the number of references */ + return NewValue; +} + +VOID +FORCEINLINE +_ObpDecrementQueryReference(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo) +{ + POBJECT_DIRECTORY Directory; + + /* Remove a query reference and check if it was the last one */ + if (!InterlockedExchangeAdd(&HeaderNameInfo->QueryReferences, -1)) + { + /* Check if we have a name */ + if (HeaderNameInfo->Name.Buffer) + { + /* We can get rid of the object name now */ + ExFreePool(HeaderNameInfo->Name.Buffer); + RtlInitEmptyUnicodeString(&HeaderNameInfo->Name, NULL, 0); + } + + /* Check if the object has a directory associated to it */ + Directory = HeaderNameInfo->Directory; + if (Directory) + { + /* Delete the directory */ + HeaderNameInfo->Directory = NULL; + ObDereferenceObjectDeferDelete(Directory); + } + } +} + +VOID +FORCEINLINE +_ObpCleanupDirectoryLookup(IN POBP_LOOKUP_CONTEXT Context, + IN BOOLEAN DereferenceObject) +{ + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO HeaderNameInfo; + + /* Check if we came back with the directory locked */ + if (Context->DirectoryLocked) + { + /* Release the lock */ + _ObpReleaseDirectoryLock(Context->Directory, Context); + } + + /* Clear the context */ + Context->Directory = NULL; + Context->DirectoryLocked = FALSE; + + /* Check if we had found an object */ + if (Context->Object) + { + /* Get the object name information */ + ObjectHeader = OBJECT_TO_OBJECT_HEADER(Context->Object); + HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + + /* Check if we do have name information */ + if (HeaderNameInfo) _ObpDecrementQueryReference(HeaderNameInfo); + + /* Check if we need to dereference it */ + if (DereferenceObject) ObDereferenceObject(Context->Object); + } +} + +VOID +FORCEINLINE +_ObpInitializeDirectoryLookup(IN POBP_LOOKUP_CONTEXT Context) +{ + /* Initialize a null context */ + Context->Object = NULL; + Context->Directory = NULL; + Context->DirectoryLocked = FALSE; + Context->LockStateSignature = 0xFFFF1234; +} + +#if _OB_DEBUG_ +#define ObpAcquireDirectoryLockShared(a, b) \ +{ \ + DbgPrint("OB QUERY: Acquiring lock at %s %d\n", __FUNCTION__, __LINE__);\ + _ObpAcquireDirectoryLockShared(a, b); \ +} +#define ObpAcquireDirectoryLockExclusive(a, b) \ +{ \ + DbgPrint("OB QUERY: Acquiring lock at %s %d\n", __FUNCTION__, __LINE__);\ + _ObpAcquireDirectoryLockExclusive(a, b); \ +} +#define ObpReleaseDirectoryLock(a, b) \ +{ \ + DbgPrint("OB QUERY: Releasing lock at %s %d\n", __FUNCTION__, __LINE__);\ + _ObpReleaseDirectoryLock(a, b); \ +} +#define ObpInitializeDirectoryLookup(a) \ +{ \ + DbgPrint("OB QUERY: Initialization at %s %d\n", __FUNCTION__, __LINE__);\ + _ObpInitializeDirectoryLookup(a); \ +} +#define ObpCleanupDirectoryLookup(a, b) \ +{ \ + DbgPrint("OB QUERY: Cleanup at %s %d\n", __FUNCTION__, __LINE__); \ + _ObpCleanupDirectoryLookup(a, b); \ +} +#define ObpDecrementQueryReference(a) \ +{ \ + DbgPrint("OB QUERY: Decrement at %s %d\n", __FUNCTION__, __LINE__); \ + _ObpDecrementQueryReference(a); \ +} +#else +#define ObpDecrementQueryReference _ObpDecrementQueryReference +#define ObpAcquireDirectoryLockExclusive _ObpAcquireDirectoryLockExclusive +#define ObpAcquireDirectoryLockShared _ObpAcquireDirectoryLockShared +#define ObpReleaseDirectoryLock _ObpReleaseDirectoryLock +#define ObpInitializeDirectoryLookup _ObpInitializeDirectoryLookup +#define ObpCleanupDirectoryLookup _ObpCleanupDirectoryLookup +#endif + VOID FORCEINLINE ObpEnterObjectTypeMutex(IN POBJECT_TYPE ObjectType) @@ -176,3 +365,5 @@ ObpFreeAndReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateIn ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList); } + + diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index 1746b437a11..66700b85e87 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -2352,6 +2352,16 @@ ObInsertObject(IN PVOID Object, ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); ObjectType = ObjectHeader->Type; + /* Check if we have name information */ + if (ObjectNameInfo) + { + /* Add a query reference */ + if (!ObpIncrementQueryReference(ObjectHeader, ObjectNameInfo)) + { + /* There are no query references, so the name info is invalid */ + ObjectNameInfo = NULL; + } + } /* Check if this is an named object */ ObjectName = NULL; @@ -2394,6 +2404,8 @@ ObInsertObject(IN PVOID Object, ObpFreeAndReleaseCapturedAttributes(ObjectCreateInfo); ObjectHeader->ObjectCreateInfo = NULL; + /* Remove a query reference if we added one */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); /* Remove the extra keep-alive reference */ if (Handle) ObDereferenceObject(Object); @@ -2419,6 +2431,7 @@ ObInsertObject(IN PVOID Object, if (!NT_SUCCESS(Status)) { /* Fail */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); ObDereferenceObject(Object); return Status; } @@ -2489,7 +2502,10 @@ ObInsertObject(IN PVOID Object, /* Check if anything until now failed */ if (!NT_SUCCESS(Status)) { - /* We failed, dereference the object and delete the access state */ + /* Remove query reference that we added */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); + + /* Dereference the object and delete the access state */ ObDereferenceObject(Object); if (AccessState == &LocalAccessState) { @@ -2554,8 +2570,10 @@ ObInsertObject(IN PVOID Object, /* Check if anything until now failed */ if (!NT_SUCCESS(Status)) { - /* We failed, dereference the object and delete the access state */ - KEBUGCHECK(0); + /* Remove query reference that we added */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); + + /* Dereference the object and delete the access state */ ObDereferenceObject(Object); if (AccessState == &LocalAccessState) { @@ -2564,6 +2582,7 @@ ObInsertObject(IN PVOID Object, } /* Return failure code */ + KEBUGCHECK(0); return Status; } } @@ -2608,8 +2627,8 @@ ObInsertObject(IN PVOID Object, RealStatus = Status; } - - + /* Remove a query reference */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); /* Remove the extra keep-alive reference */ if (Handle) ObDereferenceObject(Object); diff --git a/reactos/ntoskrnl/ob/obname.c b/reactos/ntoskrnl/ob/obname.c index c72bfe6a0fc..503a2f72b58 100644 --- a/reactos/ntoskrnl/ob/obname.c +++ b/reactos/ntoskrnl/ob/obname.c @@ -173,6 +173,17 @@ ObpDeleteNameCheck(IN PVOID Object) ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); ObjectType = ObjectHeader->Type; + /* Check if we have a name information structure */ + if (ObjectNameInfo) + { + /* Add a query reference */ + if (!ObpIncrementQueryReference(ObjectHeader, ObjectNameInfo)) + { + /* No references, so the name info is invalid */ + ObjectNameInfo = NULL; + } + } + /* * Check if the handle count is 0, if the object is named, * and if the object isn't a permanent object. @@ -182,62 +193,89 @@ ObpDeleteNameCheck(IN PVOID Object) (ObjectNameInfo->Name.Length) && !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) { + /* Setup a lookup context */ Context.Object = NULL; - /* Make sure it's still inserted */ + /* Lock the directory */ + //ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context); + + /* Set the lookup parameters */ Context.Directory = ObjectNameInfo->Directory; Context.DirectoryLocked = TRUE; + Context.LockStateSignature = 0xCCCC1234; + + /* Do the lookup */ Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, &ObjectNameInfo->Name, 0, FALSE, &Context); - if ((Object) && !(ObjectHeader->HandleCount)) + if (Object) { /* Lock the object type */ ObpEnterObjectTypeMutex(ObjectType); - /* First delete it from the directory */ - ObpDeleteEntryDirectory(&Context); - - /* Now check if we have a security callback */ - if (ObjectType->TypeInfo.SecurityRequired) + /* Make sure we can still delete the object */ + if (!(ObjectHeader->HandleCount) && + !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) { - /* Call it */ - ObjectType->TypeInfo.SecurityProcedure(Object, - DeleteSecurityDescriptor, - 0, - NULL, - NULL, - &ObjectHeader-> - SecurityDescriptor, - ObjectType-> - TypeInfo.PoolType, - NULL); + /* First delete it from the directory */ + ObpDeleteEntryDirectory(&Context); + + /* Check if this is a symbolic link */ + if (ObjectType == ObSymbolicLinkType) + { + /* Remove internal name */ + ObpDeleteSymbolicLinkName(Object); + } + + /* Add a query reference */ + ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); + if (!ObpIncrementQueryReference(ObjectHeader, ObjectNameInfo)) + { + /* No references, so the name info is invalid */ + ObjectNameInfo = NULL; + } + + /* Check if the magic protection flag is set */ + if ((ObjectNameInfo) && + (ObjectNameInfo->QueryReferences & 0x40000000)) + { + /* Add deletion flag */ + InterlockedExchangeAdd(&ObjectNameInfo->QueryReferences, + 0xC0000000); + } + + /* Get the directory */ + Directory = ObjectNameInfo->Directory; } /* Release the lock */ ObpLeaveObjectTypeMutex(ObjectType); - - /* Free the name */ - ExFreePool(ObjectNameInfo->Name.Buffer); - RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); - - Context.Object = NULL; - - /* Clear the current directory and de-reference it */ - Directory = ObjectNameInfo->Directory; - ObjectNameInfo->Directory = NULL; } + /* Cleanup after lookup */ + //ObpCleanupDirectoryLookup(&Context, TRUE); + Context.Object = NULL; + + /* Remove another query reference since we added one on top */ + ObpDecrementQueryReference(ObjectNameInfo); + /* Check if we were inserted in a directory */ if (Directory) { - /* We were, so dereference the directory and the object as well */ - ObDereferenceObject(Directory); + /* We were, so first remove the extra reference we had added */ + ObpDecrementQueryReference(ObjectNameInfo); + + /* Now dereference the object as well */ ObDereferenceObject(Object); } } + else + { + /* Remove the reference we added */ + if (ObjectNameInfo) ObpDecrementQueryReference(ObjectNameInfo); + } } NTSTATUS