diff --git a/reactos/ntoskrnl/ob/obsdcach.c b/reactos/ntoskrnl/ob/obsdcach.c index c10de3aa0b1..60fda02ca85 100644 --- a/reactos/ntoskrnl/ob/obsdcach.c +++ b/reactos/ntoskrnl/ob/obsdcach.c @@ -181,24 +181,51 @@ ObpReferenceSecurityDescriptor(IN POBJECT_HEADER ObjectHeader) { PSECURITY_DESCRIPTOR SecurityDescriptor; PSECURITY_DESCRIPTOR_HEADER SdHeader; - - /* Get the SD */ - SecurityDescriptor = ObjectHeader->SecurityDescriptor; - if (!SecurityDescriptor) + PEX_FAST_REF FastRef; + EX_FAST_REF OldValue; + ULONG_PTR Count; + + /* Acquire a reference to the security descriptor */ + FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor; + OldValue = ExAcquireFastReference(FastRef); + + /* Get the descriptor and reference count */ + SecurityDescriptor = ExGetObjectFastReference(OldValue); + Count = ExGetCountFastReference(OldValue); + + /* Check if there's no descriptor or if there's still cached references */ + if ((Count >= 1) || !(SecurityDescriptor)) { - /* No SD, nothing to do */ - return NULL; + /* Check if this is the last reference */ + if (Count == 1) + { + /* Add the extra references that we'll take */ + SdHeader = ObpGetHeaderForSd(SecurityDescriptor); + InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, MAX_FAST_REFS); + + /* Now insert them */ + if (!ExInsertFastReference(FastRef, SecurityDescriptor)) + { + /* Undo the references since we failed */ + InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, + -MAX_FAST_REFS); + } + } + + /* Return the SD */ + return SecurityDescriptor; } - + /* Lock the object */ ObpAcquireObjectLockShared(ObjectHeader); - + /* Get the object header */ + SecurityDescriptor = ExGetObjectFastReference(*FastRef); SdHeader = ObpGetHeaderForSd(SecurityDescriptor); - + /* Do the reference */ InterlockedIncrement((PLONG)&SdHeader->RefCount); - + /* Release the lock and return */ ObpReleaseObjectLock(ObjectHeader); return SecurityDescriptor; diff --git a/reactos/ntoskrnl/ob/obsecure.c b/reactos/ntoskrnl/ob/obsecure.c index 3ee899fd837..3c90e1a728f 100644 --- a/reactos/ntoskrnl/ob/obsecure.c +++ b/reactos/ntoskrnl/ob/obsecure.c @@ -24,19 +24,23 @@ ObAssignObjectSecurityDescriptor(IN PVOID Object, POBJECT_HEADER ObjectHeader; NTSTATUS Status; PSECURITY_DESCRIPTOR NewSd; + PEX_FAST_REF FastRef; PAGED_CODE(); /* Get the object header */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); + FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor; if (!SecurityDescriptor) { /* Nothing to assign */ - ObjectHeader->SecurityDescriptor = NULL; + ExInitializeFastReference(FastRef, NULL); return STATUS_SUCCESS; } /* Add it to our internal cache */ - Status = ObLogSecurityDescriptor(SecurityDescriptor, &NewSd, 1); + Status = ObLogSecurityDescriptor(SecurityDescriptor, + &NewSd, + MAX_FAST_REFS + 1); if (NT_SUCCESS(Status)) { /* Free the old copy */ @@ -44,7 +48,7 @@ ObAssignObjectSecurityDescriptor(IN PVOID Object, /* Set the new pointer */ ASSERT(NewSd); - ObjectHeader->SecurityDescriptor = NewSd; + ExInitializeFastReference(FastRef, NewSd); } /* Return status */ @@ -55,11 +59,22 @@ NTSTATUS NTAPI ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) { - /* Dereference it */ - ObDereferenceSecurityDescriptor(*SecurityDescriptor, 1); - + EX_FAST_REF FastRef; + ULONG_PTR Count; + PSECURITY_DESCRIPTOR OldSecurityDescriptor; + + /* Get the fast reference and capture it */ + FastRef = *(PEX_FAST_REF)SecurityDescriptor; + /* Don't free again later */ *SecurityDescriptor = NULL; + + /* Get the descriptor and reference count */ + OldSecurityDescriptor = ExGetObjectFastReference(FastRef); + Count = ExGetCountFastReference(FastRef); + + /* Dereference the descriptor */ + ObDereferenceSecurityDescriptor(OldSecurityDescriptor, Count + 1); /* All done */ return STATUS_SUCCESS; @@ -109,6 +124,9 @@ ObSetSecurityDescriptorInfo(IN PVOID Object, NTSTATUS Status; POBJECT_HEADER ObjectHeader; PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor; + PEX_FAST_REF FastRef; + EX_FAST_REF OldValue; + ULONG_PTR Count; PAGED_CODE(); /* Get the object header */ @@ -129,7 +147,9 @@ ObSetSecurityDescriptorInfo(IN PVOID Object, if (NT_SUCCESS(Status)) { /* Now add this to the cache */ - Status = ObLogSecurityDescriptor(NewDescriptor, &CachedDescriptor, 1); + Status = ObLogSecurityDescriptor(NewDescriptor, + &CachedDescriptor, + MAX_FAST_REFS + 1); /* Let go of our uncached copy */ ExFreePool(NewDescriptor); @@ -137,15 +157,34 @@ ObSetSecurityDescriptorInfo(IN PVOID Object, /* Check for success */ if (NT_SUCCESS(Status)) { - /* Dereference the old one */ - ASSERT(OldDescriptor == ObjectHeader->SecurityDescriptor); + /* Do the swap */ + FastRef = (PEX_FAST_REF)OutputSecurityDescriptor; + OldValue = ExCompareSwapFastReference(FastRef, + CachedDescriptor, + OldDescriptor); + + /* Get the security descriptor */ + SecurityDescriptor = ExGetObjectFastReference(OldValue); + Count = ExGetCountFastReference(OldValue); + + /* Make sure the swap worked */ + if (SecurityDescriptor == OldDescriptor) + { + /* Flush waiters */ + ObpAcquireObjectLock(ObjectHeader); + ObpReleaseObjectLock(ObjectHeader); - /* Now set this as the new descriptor */ - ObjectHeader->SecurityDescriptor = CachedDescriptor; - - /* And dereference the old one */ - ObDereferenceSecurityDescriptor(OldDescriptor, 1); - break; + /* And dereference the old one */ + ObDereferenceSecurityDescriptor(OldDescriptor, Count + 2); + break; + } + else + { + /* Someone changed it behind our back -- try again */ + ObDereferenceSecurityDescriptor(OldDescriptor, 1); + ObDereferenceSecurityDescriptor(CachedDescriptor, + MAX_FAST_REFS + 1); + } } else {