ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

obsdcach.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.