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