PSECURITY_DESCRIPTOR NTAPI ObpReferenceSecurityDescriptor(IN POBJECT_HEADER ObjectHeader) { PSECURITY_DESCRIPTOR SecurityDescriptor; PSECURITY_DESCRIPTOR_HEADER SdHeader; 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)) { /* 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; }
PEX_CALLBACK_ROUTINE_BLOCK NTAPI ExReferenceCallBackBlock(IN OUT PEX_CALLBACK CallBack) { EX_FAST_REF OldValue; ULONG_PTR Count; PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; /* Acquire a reference */ OldValue = ExAcquireFastReference(&CallBack->RoutineBlock); Count = ExGetCountFastReference(OldValue); /* Fail if there isn't any object */ if (!ExGetObjectFastReference(OldValue)) return NULL; /* Check if we don't have a reference */ if (!Count) { /* FIXME: Race */ DPRINT1("Unhandled callback race condition\n"); ASSERT(FALSE); return NULL; } /* Get the callback block */ CallbackBlock = ExGetObjectFastReference(OldValue); /* Check if this is the last reference */ if (Count == 1) { /* Acquire rundown protection */ if (ExfAcquireRundownProtectionEx(&CallbackBlock->RundownProtect, MAX_FAST_REFS)) { /* Insert references */ if (!ExInsertFastReference(&CallBack->RoutineBlock, CallbackBlock)) { /* Backdown the rundown acquire */ ExfReleaseRundownProtectionEx(&CallbackBlock->RundownProtect, MAX_FAST_REFS); } } } /* Return the callback block */ return CallbackBlock; }
NTSTATUS NTAPI ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) { 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; }
BOOLEAN NTAPI ExCompareExchangeCallBack(IN OUT PEX_CALLBACK CallBack, IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock, IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock) { EX_FAST_REF OldValue; PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; ULONG Count; /* Check that we have a new block */ if (NewBlock) { /* Acquire rundown */ if (!ExfAcquireRundownProtectionEx(&NewBlock->RundownProtect, MAX_FAST_REFS + 1)) { /* This should never happen */ ASSERTMSG("Callback block is already undergoing rundown", FALSE); return FALSE; } } /* Do the swap */ OldValue = ExCompareSwapFastReference(&CallBack->RoutineBlock, NewBlock, OldBlock); /* Get the routine block */ CallbackBlock = ExGetObjectFastReference(OldValue); Count = ExGetCountFastReference(OldValue); /* Make sure the swap worked */ if (CallbackBlock == OldBlock) { /* Make sure we replaced a valid pointer */ if (CallbackBlock) { /* Acquire the flush lock and immediately release it */ KeEnterCriticalRegion(); ExWaitOnPushLock(&ExpCallBackFlush); /* Release rundown protection */ KeLeaveCriticalRegion(); ExfReleaseRundownProtectionEx(&CallbackBlock->RundownProtect, Count + 1); } /* Compare worked */ return TRUE; } else { /* It failed, check if we had a block */ if (NewBlock) { /* We did, remove the refernces that we had added */ ExfReleaseRundownProtectionEx(&NewBlock->RundownProtect, MAX_FAST_REFS + 1); } /* Return failure */ return FALSE; } }
NTSTATUS NTAPI ObSetSecurityDescriptorInfo(IN PVOID Object, IN PSECURITY_INFORMATION SecurityInformation, IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor, IN POOL_TYPE PoolType, IN PGENERIC_MAPPING GenericMapping) { 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 */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); while (TRUE) { /* Reference the old descriptor */ OldDescriptor = ObpReferenceSecurityDescriptor(ObjectHeader); NewDescriptor = OldDescriptor; /* Set the SD information */ Status = SeSetSecurityDescriptorInfo(Object, SecurityInformation, SecurityDescriptor, &NewDescriptor, PoolType, GenericMapping); if (NT_SUCCESS(Status)) { /* Now add this to the cache */ Status = ObLogSecurityDescriptor(NewDescriptor, &CachedDescriptor, MAX_FAST_REFS + 1); /* Let go of our uncached copy */ ExFreePool(NewDescriptor); /* Check for success */ if (NT_SUCCESS(Status)) { /* 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); /* 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 { /* We failed, dereference the old one */ ObDereferenceSecurityDescriptor(OldDescriptor, 1); break; } } else { /* We failed, dereference the old one */ if (OldDescriptor) ObDereferenceSecurityDescriptor(OldDescriptor, 1); break; } } /* Return status */ return Status; }