2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obsdcach.c
5 * PURPOSE: Security Descriptor Caching
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 #define SD_CACHE_ENTRIES 0x100
18 OB_SD_CACHE_LIST ObsSecurityDescriptorCache
[SD_CACHE_ENTRIES
];
20 /* PRIVATE FUNCTIONS **********************************************************/
24 ObpSdAcquireLock(IN POB_SD_CACHE_LIST CacheEntry
)
26 /* Acquire the lock */
27 KeEnterCriticalRegion();
28 ExAcquirePushLockExclusive(&CacheEntry
->PushLock
);
33 ObpSdReleaseLock(IN POB_SD_CACHE_LIST CacheEntry
)
35 /* Release the lock */
36 ExReleasePushLockExclusive(&CacheEntry
->PushLock
);
37 KeLeaveCriticalRegion();
42 ObpSdAcquireLockShared(IN POB_SD_CACHE_LIST CacheEntry
)
44 /* Acquire the lock */
45 KeEnterCriticalRegion();
46 ExAcquirePushLockShared(&CacheEntry
->PushLock
);
51 ObpSdReleaseLockShared(IN POB_SD_CACHE_LIST CacheEntry
)
53 /* Release the lock */
54 ExReleasePushLock(&CacheEntry
->PushLock
);
55 KeLeaveCriticalRegion();
65 /* Loop each cache entry */
66 for (i
= 0; i
< SD_CACHE_ENTRIES
; i
++)
68 /* Initialize the lock and the list */
69 InitializeListHead(&ObsSecurityDescriptorCache
[i
].Head
);
70 ExInitializePushLock(&ObsSecurityDescriptorCache
[i
].PushLock
);
74 return STATUS_SUCCESS
;
79 ObpHash(IN PVOID Buffer
,
86 /* Setup aligned and byte buffers */
89 ppb
= (PUCHAR
)((ULONG_PTR
)Buffer
+ Length
);
90 pp
= (PULONG
)ALIGN_DOWN(pb
+ Length
, ULONG
);
92 /* Loop aligned data */
97 Hash
= _rotl(Hash
, 3);
100 /* Loop non-aligned data */
106 Hash
= _rotl(Hash
, 3);
109 /* Return the hash */
115 ObpHashSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
118 /* Just hash the entire SD */
119 return ObpHash(SecurityDescriptor
, Length
);
122 PSECURITY_DESCRIPTOR_HEADER
124 ObpCreateCacheEntry(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
130 PSECURITY_DESCRIPTOR_HEADER SdHeader
;
131 ASSERT(Length
== RtlLengthSecurityDescriptor(SecurityDescriptor
));
133 /* Calculate the memory we'll need to allocate and allocate it */
134 CacheSize
= Length
+ (sizeof(SECURITY_DESCRIPTOR_HEADER
) - sizeof(QUAD
));
135 SdHeader
= ExAllocatePoolWithTag(PagedPool
, CacheSize
, TAG_OB_SD_CACHE
);
136 if (!SdHeader
) return NULL
;
138 /* Setup the header */
139 SdHeader
->RefCount
= RefCount
;
140 SdHeader
->FullHash
= FullHash
;
142 /* Copy the descriptor */
143 RtlCopyMemory(&SdHeader
->SecurityDescriptor
, SecurityDescriptor
, Length
);
151 ObpCompareSecurityDescriptors(IN PSECURITY_DESCRIPTOR Sd1
,
153 IN PSECURITY_DESCRIPTOR Sd2
)
156 ASSERT(Length1
== RtlLengthSecurityDescriptor(Sd1
));
158 /* Get the length of the second SD */
159 Length2
= RtlLengthSecurityDescriptor(Sd2
);
161 /* Compare lengths */
162 if (Length1
!= Length2
) return FALSE
;
164 /* Compare contents */
165 return RtlEqualMemory(Sd1
, Sd2
, Length1
);
170 ObpDestroySecurityDescriptorHeader(IN PSECURITY_DESCRIPTOR_HEADER SdHeader
)
172 ASSERT(SdHeader
->RefCount
== 0);
174 /* Just unlink the SD and return it back to the caller */
175 RemoveEntryList(&SdHeader
->Link
);
181 ObpReferenceSecurityDescriptor(IN POBJECT_HEADER ObjectHeader
)
183 PSECURITY_DESCRIPTOR SecurityDescriptor
;
184 PSECURITY_DESCRIPTOR_HEADER SdHeader
;
185 PEX_FAST_REF FastRef
;
186 EX_FAST_REF OldValue
;
189 /* Acquire a reference to the security descriptor */
190 FastRef
= (PEX_FAST_REF
)&ObjectHeader
->SecurityDescriptor
;
191 OldValue
= ExAcquireFastReference(FastRef
);
193 /* Get the descriptor and reference count */
194 SecurityDescriptor
= ExGetObjectFastReference(OldValue
);
195 Count
= ExGetCountFastReference(OldValue
);
197 /* Check if there's no descriptor or if there's still cached references */
198 if ((Count
>= 1) || !(SecurityDescriptor
))
200 /* Check if this is the last reference */
203 /* Add the extra references that we'll take */
204 SdHeader
= ObpGetHeaderForSd(SecurityDescriptor
);
205 InterlockedExchangeAdd((PLONG
)&SdHeader
->RefCount
, MAX_FAST_REFS
);
207 /* Now insert them */
208 if (!ExInsertFastReference(FastRef
, SecurityDescriptor
))
210 /* Undo the references since we failed */
211 InterlockedExchangeAdd((PLONG
)&SdHeader
->RefCount
,
217 return SecurityDescriptor
;
220 /* Lock the object */
221 ObpAcquireObjectLockShared(ObjectHeader
);
223 /* Get the object header */
224 SecurityDescriptor
= ExGetObjectFastReference(*FastRef
);
225 SdHeader
= ObpGetHeaderForSd(SecurityDescriptor
);
227 /* Do the reference */
228 InterlockedIncrement((PLONG
)&SdHeader
->RefCount
);
230 /* Release the lock and return */
231 ObpReleaseObjectLock(ObjectHeader
);
232 return SecurityDescriptor
;
235 /* PUBLIC FUNCTIONS ***********************************************************/
238 * @name ObReferenceSecurityDescriptor
241 * The ObReferenceSecurityDescriptor routine <FILLMEIN>
243 * @param SecurityDescriptor
249 * @return STATUS_SUCCESS or appropriate error value.
256 ObReferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
259 PSECURITY_DESCRIPTOR_HEADER SdHeader
;
262 SdHeader
= ObpGetHeaderForSd(SecurityDescriptor
);
264 /* Do the references */
265 InterlockedExchangeAdd((PLONG
)&SdHeader
->RefCount
, Count
);
269 * @name ObDereferenceSecurityDescriptor
272 * The ObDereferenceSecurityDescriptor routine <FILLMEIN>
274 * @param SecurityDescriptor
280 * @return STATUS_SUCCESS or appropriate error value.
287 ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
290 PSECURITY_DESCRIPTOR_HEADER SdHeader
;
291 LONG OldValue
, NewValue
;
293 POB_SD_CACHE_LIST CacheEntry
;
296 SdHeader
= ObpGetHeaderForSd(SecurityDescriptor
);
298 /* Get the current reference count */
299 OldValue
= SdHeader
->RefCount
;
301 /* Check if the caller is destroying this SD -- we need the lock for that */
302 while (OldValue
!= Count
)
304 /* He isn't, we can just try to derefeference atomically */
305 NewValue
= InterlockedCompareExchange((PLONG
)&SdHeader
->RefCount
,
308 if (NewValue
== OldValue
) return;
314 /* At this point, we need the lock, so choose an entry */
315 Index
= SdHeader
->FullHash
% SD_CACHE_ENTRIES
;
316 CacheEntry
= &ObsSecurityDescriptorCache
[Index
];
318 /* Acquire the lock for it */
319 ObpSdAcquireLock(CacheEntry
);
320 ASSERT(SdHeader
->RefCount
!= 0);
322 /* Now do the dereference */
323 if (InterlockedExchangeAdd((PLONG
)&SdHeader
->RefCount
, -(LONG
)Count
) == Count
)
325 /* We're down to zero -- destroy the header */
326 SdHeader
= ObpDestroySecurityDescriptorHeader(SdHeader
);
328 /* Release the lock */
329 ObpSdReleaseLock(CacheEntry
);
331 /* Free the header */
332 ExFreePool(SdHeader
);
336 /* Just release the lock */
337 ObpSdReleaseLock(CacheEntry
);
343 * @name ObLogSecurityDescriptor
346 * The ObLogSecurityDescriptor routine <FILLMEIN>
348 * @param InputSecurityDescriptor
351 * @param OutputSecurityDescriptor
357 * @return STATUS_SUCCESS or appropriate error value.
364 ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor
,
365 OUT PSECURITY_DESCRIPTOR
*OutputSecurityDescriptor
,
368 PSECURITY_DESCRIPTOR_HEADER SdHeader
= NULL
, NewHeader
= NULL
;
369 ULONG Length
, Hash
, Index
;
370 POB_SD_CACHE_LIST CacheEntry
;
372 PLIST_ENTRY NextEntry
;
375 Length
= RtlLengthSecurityDescriptor(InputSecurityDescriptor
);
378 Hash
= ObpHashSecurityDescriptor(InputSecurityDescriptor
, Length
);
380 /* Now select the appropriate cache entry */
381 Index
= Hash
% SD_CACHE_ENTRIES
;
382 CacheEntry
= &ObsSecurityDescriptorCache
[Index
];
385 ObpSdAcquireLockShared(CacheEntry
);
387 /* Start our search */
390 /* Reset result found */
393 /* Loop the hash list */
394 NextEntry
= CacheEntry
->Head
.Flink
;
395 while (NextEntry
!= &CacheEntry
->Head
)
398 SdHeader
= ObpGetHeaderForEntry(NextEntry
);
400 /* Our hashes are ordered, so quickly check if we should stop now */
401 if (SdHeader
->FullHash
> Hash
) break;
403 /* We survived the quick hash check, now check for equalness */
404 if (SdHeader
->FullHash
== Hash
)
406 /* Hashes match, now compare descriptors */
407 Result
= ObpCompareSecurityDescriptors(InputSecurityDescriptor
,
409 &SdHeader
->SecurityDescriptor
);
413 /* Go to the next entry */
414 NextEntry
= NextEntry
->Flink
;
417 /* Check if we found anything */
420 /* Increment its reference count */
421 InterlockedExchangeAdd((PLONG
)&SdHeader
->RefCount
, RefBias
);
423 /* Release the lock */
424 ObpSdReleaseLockShared(CacheEntry
);
426 /* Return the descriptor */
427 *OutputSecurityDescriptor
= &SdHeader
->SecurityDescriptor
;
429 /* Free anything that we may have had to create */
430 if (NewHeader
) ExFreePoolWithTag(NewHeader
, TAG_OB_SD_CACHE
);
431 return STATUS_SUCCESS
;
434 /* Check if we got here, and didn't create a descriptor yet */
437 /* Release the lock */
438 ObpSdReleaseLockShared(CacheEntry
);
440 /* This should be our first time in the loop, create it */
441 NewHeader
= ObpCreateCacheEntry(InputSecurityDescriptor
,
445 if (!NewHeader
) return STATUS_INSUFFICIENT_RESOURCES
;
447 /* Now acquire the exclusive lock and we should hit the right path */
448 ObpSdAcquireLock(CacheEntry
);
452 /* We have inserted the SD, we're fine now */
457 /* Okay, now let's do the insert, we should have the exclusive lock */
458 InsertTailList(NextEntry
, &NewHeader
->Link
);
460 /* Release the lock */
461 ObpSdReleaseLock(CacheEntry
);
464 *OutputSecurityDescriptor
= &NewHeader
->SecurityDescriptor
;
465 return STATUS_SUCCESS
;