Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenobsdcach.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ob/obsdcach.c 00005 * PURPOSE: Security Descriptor Caching 00006 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* GLOBALS ********************************************************************/ 00016 00017 #define SD_CACHE_ENTRIES 0x100 00018 OB_SD_CACHE_LIST ObsSecurityDescriptorCache[SD_CACHE_ENTRIES]; 00019 00020 /* PRIVATE FUNCTIONS **********************************************************/ 00021 00022 FORCEINLINE 00023 VOID 00024 ObpSdAcquireLock(IN POB_SD_CACHE_LIST CacheEntry) 00025 { 00026 /* Acquire the lock */ 00027 KeEnterCriticalRegion(); 00028 ExAcquirePushLockExclusive(&CacheEntry->PushLock); 00029 } 00030 00031 FORCEINLINE 00032 VOID 00033 ObpSdReleaseLock(IN POB_SD_CACHE_LIST CacheEntry) 00034 { 00035 /* Release the lock */ 00036 ExReleasePushLockExclusive(&CacheEntry->PushLock); 00037 KeLeaveCriticalRegion(); 00038 } 00039 00040 FORCEINLINE 00041 VOID 00042 ObpSdAcquireLockShared(IN POB_SD_CACHE_LIST CacheEntry) 00043 { 00044 /* Acquire the lock */ 00045 KeEnterCriticalRegion(); 00046 ExAcquirePushLockShared(&CacheEntry->PushLock); 00047 } 00048 00049 FORCEINLINE 00050 VOID 00051 ObpSdReleaseLockShared(IN POB_SD_CACHE_LIST CacheEntry) 00052 { 00053 /* Release the lock */ 00054 ExReleasePushLock(&CacheEntry->PushLock); 00055 KeLeaveCriticalRegion(); 00056 } 00057 00058 NTSTATUS 00059 NTAPI 00060 INIT_FUNCTION 00061 ObpInitSdCache(VOID) 00062 { 00063 ULONG i; 00064 00065 /* Loop each cache entry */ 00066 for (i = 0; i < SD_CACHE_ENTRIES; i++) 00067 { 00068 /* Initialize the lock and the list */ 00069 InitializeListHead(&ObsSecurityDescriptorCache[i].Head); 00070 ExInitializePushLock(&ObsSecurityDescriptorCache[i].PushLock); 00071 } 00072 00073 /* Return success */ 00074 return STATUS_SUCCESS; 00075 } 00076 00077 ULONG 00078 NTAPI 00079 ObpHash(IN PVOID Buffer, 00080 IN ULONG Length) 00081 { 00082 PULONG p, pp; 00083 PUCHAR pb, ppb; 00084 ULONG Hash = 0; 00085 00086 /* Setup aligned and byte buffers */ 00087 p = Buffer; 00088 pb = (PUCHAR)p; 00089 ppb = (PUCHAR)((ULONG_PTR)Buffer + Length); 00090 pp = (PULONG)ALIGN_DOWN(pb + Length, ULONG); 00091 00092 /* Loop aligned data */ 00093 while (p < pp) 00094 { 00095 /* XOR-rotate */ 00096 Hash ^= *p++; 00097 Hash = _rotl(Hash, 3); 00098 } 00099 00100 /* Loop non-aligned data */ 00101 pb = (PUCHAR)p; 00102 while (pb < ppb) 00103 { 00104 /* XOR-rotate */ 00105 Hash ^= *pb++; 00106 Hash = _rotl(Hash, 3); 00107 } 00108 00109 /* Return the hash */ 00110 return Hash; 00111 } 00112 00113 ULONG 00114 NTAPI 00115 ObpHashSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor, 00116 IN ULONG Length) 00117 { 00118 /* Just hash the entire SD */ 00119 return ObpHash(SecurityDescriptor, Length); 00120 } 00121 00122 PSECURITY_DESCRIPTOR_HEADER 00123 NTAPI 00124 ObpCreateCacheEntry(IN PSECURITY_DESCRIPTOR SecurityDescriptor, 00125 IN ULONG Length, 00126 IN ULONG FullHash, 00127 IN ULONG RefCount) 00128 { 00129 ULONG CacheSize; 00130 PSECURITY_DESCRIPTOR_HEADER SdHeader; 00131 ASSERT(Length == RtlLengthSecurityDescriptor(SecurityDescriptor)); 00132 00133 /* Calculate the memory we'll need to allocate and allocate it */ 00134 CacheSize = Length + (sizeof(SECURITY_DESCRIPTOR_HEADER) - sizeof(QUAD)); 00135 SdHeader = ExAllocatePoolWithTag(PagedPool, CacheSize, TAG_OB_SD_CACHE); 00136 if (!SdHeader) return NULL; 00137 00138 /* Setup the header */ 00139 SdHeader->RefCount = RefCount; 00140 SdHeader->FullHash = FullHash; 00141 00142 /* Copy the descriptor */ 00143 RtlCopyMemory(&SdHeader->SecurityDescriptor, SecurityDescriptor, Length); 00144 00145 /* Return it */ 00146 return SdHeader; 00147 } 00148 00149 BOOLEAN 00150 NTAPI 00151 ObpCompareSecurityDescriptors(IN PSECURITY_DESCRIPTOR Sd1, 00152 IN ULONG Length1, 00153 IN PSECURITY_DESCRIPTOR Sd2) 00154 { 00155 ULONG Length2; 00156 ASSERT(Length1 == RtlLengthSecurityDescriptor(Sd1)); 00157 00158 /* Get the length of the second SD */ 00159 Length2 = RtlLengthSecurityDescriptor(Sd2); 00160 00161 /* Compare lengths */ 00162 if (Length1 != Length2) return FALSE; 00163 00164 /* Compare contents */ 00165 return RtlEqualMemory(Sd1, Sd2, Length1); 00166 } 00167 00168 PVOID 00169 NTAPI 00170 ObpDestroySecurityDescriptorHeader(IN PSECURITY_DESCRIPTOR_HEADER SdHeader) 00171 { 00172 ASSERT(SdHeader->RefCount == 0); 00173 00174 /* Just unlink the SD and return it back to the caller */ 00175 RemoveEntryList(&SdHeader->Link); 00176 return SdHeader; 00177 } 00178 00179 PSECURITY_DESCRIPTOR 00180 NTAPI 00181 ObpReferenceSecurityDescriptor(IN POBJECT_HEADER ObjectHeader) 00182 { 00183 PSECURITY_DESCRIPTOR SecurityDescriptor; 00184 PSECURITY_DESCRIPTOR_HEADER SdHeader; 00185 PEX_FAST_REF FastRef; 00186 EX_FAST_REF OldValue; 00187 ULONG_PTR Count; 00188 00189 /* Acquire a reference to the security descriptor */ 00190 FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor; 00191 OldValue = ExAcquireFastReference(FastRef); 00192 00193 /* Get the descriptor and reference count */ 00194 SecurityDescriptor = ExGetObjectFastReference(OldValue); 00195 Count = ExGetCountFastReference(OldValue); 00196 00197 /* Check if there's no descriptor or if there's still cached references */ 00198 if ((Count >= 1) || !(SecurityDescriptor)) 00199 { 00200 /* Check if this is the last reference */ 00201 if (Count == 1) 00202 { 00203 /* Add the extra references that we'll take */ 00204 SdHeader = ObpGetHeaderForSd(SecurityDescriptor); 00205 InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, MAX_FAST_REFS); 00206 00207 /* Now insert them */ 00208 if (!ExInsertFastReference(FastRef, SecurityDescriptor)) 00209 { 00210 /* Undo the references since we failed */ 00211 InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, 00212 -MAX_FAST_REFS); 00213 } 00214 } 00215 00216 /* Return the SD */ 00217 return SecurityDescriptor; 00218 } 00219 00220 /* Lock the object */ 00221 ObpAcquireObjectLockShared(ObjectHeader); 00222 00223 /* Get the object header */ 00224 SecurityDescriptor = ExGetObjectFastReference(*FastRef); 00225 SdHeader = ObpGetHeaderForSd(SecurityDescriptor); 00226 00227 /* Do the reference */ 00228 InterlockedIncrement((PLONG)&SdHeader->RefCount); 00229 00230 /* Release the lock and return */ 00231 ObpReleaseObjectLock(ObjectHeader); 00232 return SecurityDescriptor; 00233 } 00234 00235 /* PUBLIC FUNCTIONS ***********************************************************/ 00236 00237 /*++ 00238 * @name ObReferenceSecurityDescriptor 00239 * @implemented NT5.2 00240 * 00241 * The ObReferenceSecurityDescriptor routine <FILLMEIN> 00242 * 00243 * @param SecurityDescriptor 00244 * <FILLMEIN> 00245 * 00246 * @param Count 00247 * <FILLMEIN> 00248 * 00249 * @return STATUS_SUCCESS or appropriate error value. 00250 * 00251 * @remarks None. 00252 * 00253 *--*/ 00254 VOID 00255 NTAPI 00256 ObReferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor, 00257 IN ULONG Count) 00258 { 00259 PSECURITY_DESCRIPTOR_HEADER SdHeader; 00260 00261 /* Get the header */ 00262 SdHeader = ObpGetHeaderForSd(SecurityDescriptor); 00263 00264 /* Do the references */ 00265 InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, Count); 00266 } 00267 00268 /*++ 00269 * @name ObDereferenceSecurityDescriptor 00270 * @implemented NT5.2 00271 * 00272 * The ObDereferenceSecurityDescriptor routine <FILLMEIN> 00273 * 00274 * @param SecurityDescriptor 00275 * <FILLMEIN> 00276 * 00277 * @param Count 00278 * <FILLMEIN> 00279 * 00280 * @return STATUS_SUCCESS or appropriate error value. 00281 * 00282 * @remarks None. 00283 * 00284 *--*/ 00285 VOID 00286 NTAPI 00287 ObDereferenceSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor, 00288 IN ULONG Count) 00289 { 00290 PSECURITY_DESCRIPTOR_HEADER SdHeader; 00291 LONG OldValue, NewValue; 00292 ULONG Index; 00293 POB_SD_CACHE_LIST CacheEntry; 00294 00295 /* Get the header */ 00296 SdHeader = ObpGetHeaderForSd(SecurityDescriptor); 00297 00298 /* Get the current reference count */ 00299 OldValue = SdHeader->RefCount; 00300 00301 /* Check if the caller is destroying this SD -- we need the lock for that */ 00302 while (OldValue != Count) 00303 { 00304 /* He isn't, we can just try to derefeference atomically */ 00305 NewValue = InterlockedCompareExchange((PLONG)&SdHeader->RefCount, 00306 OldValue - Count, 00307 OldValue); 00308 if (NewValue == OldValue) return; 00309 00310 /* Try again */ 00311 OldValue = NewValue; 00312 } 00313 00314 /* At this point, we need the lock, so choose an entry */ 00315 Index = SdHeader->FullHash % SD_CACHE_ENTRIES; 00316 CacheEntry = &ObsSecurityDescriptorCache[Index]; 00317 00318 /* Acquire the lock for it */ 00319 ObpSdAcquireLock(CacheEntry); 00320 ASSERT(SdHeader->RefCount != 0); 00321 00322 /* Now do the dereference */ 00323 if (InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, -(LONG)Count) == Count) 00324 { 00325 /* We're down to zero -- destroy the header */ 00326 SdHeader = ObpDestroySecurityDescriptorHeader(SdHeader); 00327 00328 /* Release the lock */ 00329 ObpSdReleaseLock(CacheEntry); 00330 00331 /* Free the header */ 00332 ExFreePool(SdHeader); 00333 } 00334 else 00335 { 00336 /* Just release the lock */ 00337 ObpSdReleaseLock(CacheEntry); 00338 } 00339 00340 } 00341 00342 /*++ 00343 * @name ObLogSecurityDescriptor 00344 * @implemented NT5.2 00345 * 00346 * The ObLogSecurityDescriptor routine <FILLMEIN> 00347 * 00348 * @param InputSecurityDescriptor 00349 * <FILLMEIN> 00350 * 00351 * @param OutputSecurityDescriptor 00352 * <FILLMEIN> 00353 * 00354 * @param RefBias 00355 * <FILLMEIN> 00356 * 00357 * @return STATUS_SUCCESS or appropriate error value. 00358 * 00359 * @remarks None. 00360 * 00361 *--*/ 00362 NTSTATUS 00363 NTAPI 00364 ObLogSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputSecurityDescriptor, 00365 OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor, 00366 IN ULONG RefBias) 00367 { 00368 PSECURITY_DESCRIPTOR_HEADER SdHeader = NULL, NewHeader = NULL; 00369 ULONG Length, Hash, Index; 00370 POB_SD_CACHE_LIST CacheEntry; 00371 BOOLEAN Result; 00372 PLIST_ENTRY NextEntry; 00373 00374 /* Get the length */ 00375 Length = RtlLengthSecurityDescriptor(InputSecurityDescriptor); 00376 00377 /* Get the hash */ 00378 Hash = ObpHashSecurityDescriptor(InputSecurityDescriptor, Length); 00379 00380 /* Now select the appropriate cache entry */ 00381 Index = Hash % SD_CACHE_ENTRIES; 00382 CacheEntry = &ObsSecurityDescriptorCache[Index]; 00383 00384 /* Lock it shared */ 00385 ObpSdAcquireLockShared(CacheEntry); 00386 00387 /* Start our search */ 00388 while (TRUE) 00389 { 00390 /* Reset result found */ 00391 Result = FALSE; 00392 00393 /* Loop the hash list */ 00394 NextEntry = CacheEntry->Head.Flink; 00395 while (NextEntry != &CacheEntry->Head) 00396 { 00397 /* Get the header */ 00398 SdHeader = ObpGetHeaderForEntry(NextEntry); 00399 00400 /* Our hashes are ordered, so quickly check if we should stop now */ 00401 if (SdHeader->FullHash > Hash) break; 00402 00403 /* We survived the quick hash check, now check for equalness */ 00404 if (SdHeader->FullHash == Hash) 00405 { 00406 /* Hashes match, now compare descriptors */ 00407 Result = ObpCompareSecurityDescriptors(InputSecurityDescriptor, 00408 Length, 00409 &SdHeader->SecurityDescriptor); 00410 if (Result) break; 00411 } 00412 00413 /* Go to the next entry */ 00414 NextEntry = NextEntry->Flink; 00415 } 00416 00417 /* Check if we found anything */ 00418 if (Result) 00419 { 00420 /* Increment its reference count */ 00421 InterlockedExchangeAdd((PLONG)&SdHeader->RefCount, RefBias); 00422 00423 /* Release the lock */ 00424 ObpSdReleaseLockShared(CacheEntry); 00425 00426 /* Return the descriptor */ 00427 *OutputSecurityDescriptor = &SdHeader->SecurityDescriptor; 00428 00429 /* Free anything that we may have had to create */ 00430 if (NewHeader) ExFreePool(NewHeader); 00431 return STATUS_SUCCESS; 00432 } 00433 00434 /* Check if we got here, and didn't create a descriptor yet */ 00435 if (!NewHeader) 00436 { 00437 /* Release the lock */ 00438 ObpSdReleaseLockShared(CacheEntry); 00439 00440 /* This should be our first time in the loop, create it */ 00441 NewHeader = ObpCreateCacheEntry(InputSecurityDescriptor, 00442 Length, 00443 Hash, 00444 RefBias); 00445 if (!NewHeader) return STATUS_INSUFFICIENT_RESOURCES; 00446 00447 /* Now acquire the exclusive lock and we should hit the right path */ 00448 ObpSdAcquireLock(CacheEntry); 00449 } 00450 else 00451 { 00452 /* We have inserted the SD, we're fine now */ 00453 break; 00454 } 00455 } 00456 00457 /* Okay, now let's do the insert, we should have the exclusive lock */ 00458 InsertTailList(NextEntry, &NewHeader->Link); 00459 00460 /* Release the lock */ 00461 ObpSdReleaseLock(CacheEntry); 00462 00463 /* Return the SD*/ 00464 *OutputSecurityDescriptor = &NewHeader->SecurityDescriptor; 00465 return STATUS_SUCCESS; 00466 } 00467 00468 /* EOF */ Generated on Fri May 25 2012 04:36:05 for ReactOS by
1.7.6.1
|