-
Notifications
You must be signed in to change notification settings - Fork 247
/
Copy pathobsdata.c
896 lines (609 loc) · 21.5 KB
/
obsdata.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
obsdata.c
Abstract:
Object Manager Security Descriptor Caching
Revision History:
General cleanup. Don't free/allocate pool under locks. Don't do unaligned fetches during hashing.
Reduce lock contention etc. Add fast referencing of security descriptor.
--*/
#include "obp.h"
#if DBG
#define OB_DIAGNOSTICS_ENABLED 1
#endif // DBG
//
// These definitions are useful diagnostics aids
//
#if OB_DIAGNOSTICS_ENABLED
//
// Test for enabled diagnostic
//
#define IF_OB_GLOBAL( FlagName ) if (ObsDebugFlags & (OBS_DEBUG_##FlagName))
//
// Diagnostics print statement
//
#define ObPrint( FlagName, _Text_ ) IF_OB_GLOBAL( FlagName ) DbgPrint _Text_
#else
//
// diagnostics not enabled - No diagnostics included in build
//
//
// Test for diagnostics enabled
//
#define IF_OB_GLOBAL( FlagName ) if (FALSE)
//
// Diagnostics print statement (expands to no-op)
//
#define ObPrint( FlagName, _Text_ ) ;
#endif // OB_DIAGNOSTICS_ENABLED
//
// The following flags enable or disable various diagnostic
// capabilities within OB code. These flags are set in
// ObGlobalFlag (only available within a DBG system).
//
//
#define OBS_DEBUG_ALLOC_TRACKING ((ULONG) 0x00000001L)
#define OBS_DEBUG_CACHE_FREES ((ULONG) 0x00000002L)
#define OBS_DEBUG_BREAK_ON_INIT ((ULONG) 0x00000004L)
#define OBS_DEBUG_SHOW_COLLISIONS ((ULONG) 0x00000008L)
#define OBS_DEBUG_SHOW_STATISTICS ((ULONG) 0x00000010L)
#define OBS_DEBUG_SHOW_REFERENCES ((ULONG) 0x00000020L)
#define OBS_DEBUG_SHOW_DEASSIGN ((ULONG) 0x00000040L)
#define OBS_DEBUG_STOP_INVALID_DESCRIPTOR ((ULONG) 0x00000080L)
#define OBS_DEBUG_SHOW_HEADER_FREE ((ULONG) 0x00000100L)
//
// Define struct of single hash clash chain
//
typedef struct _OB_SD_CACHE_LIST {
EX_PUSH_LOCK PushLock;
LIST_ENTRY Head;
} OB_SD_CACHE_LIST, *POB_SD_CACHE_LIST;
//
// Array of pointers to security descriptor entries
//
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
OB_SD_CACHE_LIST ObsSecurityDescriptorCache[SECURITY_DESCRIPTOR_CACHE_ENTRIES];
#if OB_DIAGNOSTICS_ENABLED
LONG ObsTotalCacheEntries = 0;
ULONG ObsDebugFlags = 0;
#endif
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT,ObpInitSecurityDescriptorCache)
#pragma alloc_text(PAGE,ObpHashSecurityDescriptor)
#pragma alloc_text(PAGE,ObpHashBuffer)
#pragma alloc_text(PAGE,ObLogSecurityDescriptor)
#pragma alloc_text(PAGE,ObpCreateCacheEntry)
#pragma alloc_text(PAGE,ObpReferenceSecurityDescriptor)
#pragma alloc_text(PAGE,ObDeassignSecurity)
#pragma alloc_text(PAGE,ObDereferenceSecurityDescriptor)
#pragma alloc_text(PAGE,ObpDestroySecurityDescriptorHeader)
#pragma alloc_text(PAGE,ObpCompareSecurityDescriptors)
#pragma alloc_text(PAGE,ObReferenceSecurityDescriptor)
#endif
NTSTATUS
ObpInitSecurityDescriptorCache (
VOID
)
/*++
Routine Description:
Allocates and initializes the globalSecurity Descriptor Cache
Arguments:
None
Return Value:
STATUS_SUCCESS on success, NTSTATUS on failure.
--*/
{
ULONG i;
IF_OB_GLOBAL( BREAK_ON_INIT ) {
DbgBreakPoint();
}
//
// Initialize all the list heads and their associated locks.
//
for (i = 0; i < SECURITY_DESCRIPTOR_CACHE_ENTRIES; i++) {
ExInitializePushLock (&ObsSecurityDescriptorCache[i].PushLock);
InitializeListHead (&ObsSecurityDescriptorCache[i].Head);
}
//
// And return to our caller
//
return( STATUS_SUCCESS );
}
ULONG
ObpHashSecurityDescriptor (
PSECURITY_DESCRIPTOR SecurityDescriptor,
ULONG Length
)
/*++
Routine Description:
Hashes a security descriptor to a 32 bit value
Arguments:
SecurityDescriptor - Provides the security descriptor to be hashed
Length - Length of security descriptor
Return Value:
ULONG - a 32 bit hash value.
--*/
{
ULONG Hash;
Hash = ObpHashBuffer (SecurityDescriptor, Length);
return Hash;
}
ULONG
ObpHashBuffer (
PVOID Data,
ULONG Length
)
/*++
Routine Description:
Hashes a buffer into a 32 bit value
Arguments:
Data - Buffer containing the data to be hashed.
Length - The length in bytes of the buffer
Return Value:
ULONG - a 32 bit hash value.
--*/
{
PULONG Buffer, BufferEnd;
PUCHAR Bufferp, BufferEndp;
ULONG Result = 0;
//
// Calculate buffer bounds as byte pointers
//
Bufferp = Data;
BufferEndp = Bufferp + Length;
//
// Calculate buffer bounds as rounded down ULONG pointers
//
Buffer = Data;
BufferEnd = (PULONG)(Bufferp + (Length&~(sizeof (ULONG) - 1)));
//
// Loop over a whole number of ULONGs
//
while (Buffer < BufferEnd) {
Result ^= *Buffer++;
Result = _rotl (Result, 3);
}
//
// Pull in the remaining bytes
//
Bufferp = (PUCHAR) Buffer;
while (Bufferp < BufferEndp) {
Result ^= *Bufferp++;
Result = _rotl (Result, 3);
}
return Result;
}
NTSTATUS
ObLogSecurityDescriptor (
__in PSECURITY_DESCRIPTOR InputSecurityDescriptor,
__out PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
__in ULONG RefBias
)
/*++
Routine Description:
Takes a passed security descriptor and registers it into the
security descriptor database.
Arguments:
InputSecurityDescriptor - The new security descriptor to be logged into
the database. On a successful return this memory will have been
freed back to pool.
OutputSecurityDescriptor - Output security descriptor to be used by the
caller.
RefBias - Amount to bias the security descriptor reference count by.
Typically either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
Return Value:
An appropriate status value
--*/
{
ULONG FullHash;
ULONG Slot;
PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
PLIST_ENTRY Front;
PSECURITY_DESCRIPTOR_HEADER Header = NULL;
BOOLEAN Match;
POB_SD_CACHE_LIST Chain;
PETHREAD CurrentThread;
ULONG Length;
Length = RtlLengthSecurityDescriptor (InputSecurityDescriptor);
FullHash = ObpHashSecurityDescriptor (InputSecurityDescriptor, Length);
Slot = FullHash % SECURITY_DESCRIPTOR_CACHE_ENTRIES;
NewDescriptor = NULL;
//
// First lock the table for read access. We will change this to write if we have to insert later
//
Chain = &ObsSecurityDescriptorCache[Slot];
CurrentThread = PsGetCurrentThread ();
KeEnterCriticalRegionThread (&CurrentThread->Tcb);
ExAcquirePushLockShared (&Chain->PushLock);
do {
//
// See if the list for this slot is in use.
// Lock the table first, unlock if if we don't need it.
//
Match = FALSE;
//
// Zoom down the hash bucket looking for a full hash match
//
for (Front = Chain->Head.Flink;
Front != &Chain->Head;
Front = Front->Flink) {
Header = LINK_TO_SD_HEADER (Front);
//
// The list is ordered by full hash value and is maintained this way by virtue
// of the fact that we use the 'Back' variable for the insert.
//
if (Header->FullHash > FullHash) {
break;
}
if (Header->FullHash == FullHash) {
Match = ObpCompareSecurityDescriptors (InputSecurityDescriptor,
Length,
&Header->SecurityDescriptor);
if (Match) {
break;
}
ObPrint (SHOW_COLLISIONS, ("Got a collision on %d, no match\n", Slot));
}
}
//
// If we have a match then we'll get the caller to use the old
// cached descriptor, but bumping its ref count, freeing what
// the caller supplied and returning the old one to our caller
//
if (Match) {
InterlockedExchangeAdd ((PLONG)&Header->RefCount, RefBias);
ObPrint (SHOW_REFERENCES, ("Reference Hash = 0x%lX, New RefCount = %d\n", Header->FullHash, Header->RefCount));
ExReleasePushLock (&Chain->PushLock);
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
*OutputSecurityDescriptor = &Header->SecurityDescriptor;
if (NewDescriptor != NULL) {
ExFreePool (NewDescriptor);
}
return STATUS_SUCCESS;
}
if (NewDescriptor == NULL) {
ExReleasePushLockShared (&Chain->PushLock);
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
//
// Can't use an existing one, create a new entry
// and insert it into the list.
//
NewDescriptor = ObpCreateCacheEntry (InputSecurityDescriptor,
Length,
FullHash,
RefBias);
if (NewDescriptor == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Reacquire the lock in write mode. We will probably have to insert now
//
KeEnterCriticalRegionThread (&CurrentThread->Tcb);
ExAcquirePushLockExclusive (&Chain->PushLock);
} else {
break;
}
} while (1);
#if OB_DIAGNOSTICS_ENABLED
InterlockedIncrement (&ObsTotalCacheEntries);
#endif
ObPrint (SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n", ObsTotalCacheEntries));
ObPrint (SHOW_COLLISIONS, ("Adding new entry for index #%d \n", Slot));
//
// Insert the entry before the 'Front' entry. If there is no 'Front' entry then this
// is just inserting at the head
//
InsertTailList (Front, &NewDescriptor->Link);
ExReleasePushLockExclusive (&Chain->PushLock);
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
//
// Set the output security descriptor and return to our caller
//
*OutputSecurityDescriptor = &NewDescriptor->SecurityDescriptor;
return( STATUS_SUCCESS );
}
PSECURITY_DESCRIPTOR_HEADER
ObpCreateCacheEntry (
PSECURITY_DESCRIPTOR InputSecurityDescriptor,
ULONG SecurityDescriptorLength,
ULONG FullHash,
ULONG RefBias
)
/*++
Routine Description:
Allocates and initializes a new cache entry.
Arguments:
InputSecurityDescriptor - The security descriptor to be cached.
Length - Length of security descriptor
FullHash - Full 32 bit hash of the security descriptor.
RefBias - Amount to bias the security descriptor reference count by.
Typically either 1 or ExFastRefGetAdditionalReferenceCount () + 1,
Return Value:
A pointer to the newly allocated cache entry, or NULL
--*/
{
ULONG CacheEntrySize;
PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
//
// Compute the size that we'll need to allocate. We need space for
// the security descriptor cache minus the funny quad at the end and the
// security descriptor itself.
//
ASSERT (SecurityDescriptorLength == RtlLengthSecurityDescriptor (InputSecurityDescriptor));
CacheEntrySize = SecurityDescriptorLength + (sizeof (SECURITY_DESCRIPTOR_HEADER) - sizeof(QUAD));
//
// Now allocate space for the cached entry
//
NewDescriptor = ExAllocatePoolWithTag (PagedPool, CacheEntrySize, 'cSbO');
if (NewDescriptor == NULL) {
return NULL;
}
//
// Fill the header, copy over the descriptor data, and return to our
// caller
//
NewDescriptor->RefCount = RefBias;
NewDescriptor->FullHash = FullHash;
RtlCopyMemory (&NewDescriptor->SecurityDescriptor,
InputSecurityDescriptor,
SecurityDescriptorLength);
return NewDescriptor;
}
VOID
ObReferenceSecurityDescriptor (
__in PSECURITY_DESCRIPTOR SecurityDescriptor,
__in ULONG Count
)
/*++
Routine Description:
References the security descriptor.
Arguments:
SecurityDescriptor - Security descriptor inside the cache to reference.
Count - Amount to reference by
Return Value:
None.
--*/
{
PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
SecurityDescriptorHeader->RefCount));
//
// Increment the reference count
//
InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, Count);
}
PSECURITY_DESCRIPTOR
ObpReferenceSecurityDescriptor (
POBJECT_HEADER ObjectHeader
)
/*++
Routine Description:
References the security descriptor of the passed object.
Arguments:
Object - Object being access validated.
Return Value:
The security descriptor of the object.
--*/
{
PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
PSECURITY_DESCRIPTOR SecurityDescriptor;
PEX_FAST_REF FastRef;
EX_FAST_REF OldRef;
ULONG RefsToAdd, Unused;
//
// Attempt the fast reference
//
FastRef = (PEX_FAST_REF) &ObjectHeader->SecurityDescriptor;
OldRef = ExFastReference (FastRef);
SecurityDescriptor = ExFastRefGetObject (OldRef);
//
// See if we can fast reference this security descriptor. Return NULL if there wasn't one
// and go the slow way if there are no more cached references left.
//
Unused = ExFastRefGetUnusedReferences (OldRef);
if (Unused >= 1 || SecurityDescriptor == NULL) {
if (Unused == 1) {
//
// If we took the counter to zero then attempt to make life easier for
// the next referencer by resetting the counter to its max. Since we now
// have a reference to the security descriptor we can do this.
//
RefsToAdd = ExFastRefGetAdditionalReferenceCount ();
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, RefsToAdd);
//
// Try to add the added references to the cache. If we fail then just
// release them. This dereference can not take the reference count to zero.
//
if (!ExFastRefAddAdditionalReferenceCounts (FastRef, SecurityDescriptor, RefsToAdd)) {
InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, -(LONG)RefsToAdd);
}
}
return SecurityDescriptor;
}
ObpLockObjectShared( ObjectHeader );
SecurityDescriptor = ExFastRefGetObject (*FastRef);
IF_OB_GLOBAL( STOP_INVALID_DESCRIPTOR ) {
if(!RtlValidSecurityDescriptor ( SecurityDescriptor )) {
DbgBreakPoint();
}
}
//
// The objects security descriptor is not allowed to go fron NON-NULL to NULL.
//
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
ObPrint( SHOW_REFERENCES, ("Referencing Hash %lX, Refcount = %d \n",SecurityDescriptorHeader->FullHash,
SecurityDescriptorHeader->RefCount));
//
// Increment the reference count
//
InterlockedIncrement ((PLONG) &SecurityDescriptorHeader->RefCount);
ObpUnlockObject( ObjectHeader );
return( SecurityDescriptor );
}
NTSTATUS
ObDeassignSecurity (
IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor
)
/*++
Routine Description:
This routine dereferences the input security descriptor
Arguments:
SecurityDescriptor - Supplies the security descriptor
being modified
Return Value:
Only returns STATUS_SUCCESS
--*/
{
PSECURITY_DESCRIPTOR SecurityDescriptor;
EX_FAST_REF FastRef;
ObPrint( SHOW_DEASSIGN,("Deassigning security descriptor %x\n",*pSecurityDescriptor));
//
// NULL out the SecurityDescriptor in the object's
// header so we don't try to free it again.
//
FastRef = *(PEX_FAST_REF) pSecurityDescriptor;
*pSecurityDescriptor = NULL;
SecurityDescriptor = ExFastRefGetObject (FastRef);
ObDereferenceSecurityDescriptor (SecurityDescriptor, ExFastRefGetUnusedReferences (FastRef) + 1);
return STATUS_SUCCESS;
}
VOID
ObDereferenceSecurityDescriptor (
__in PSECURITY_DESCRIPTOR SecurityDescriptor,
__in ULONG Count
)
/*++
Routine Description:
Decrements the refcount of a cached security descriptor
Arguments:
SecurityDescriptor - Points to a cached security descriptor
Return Value:
None.
--*/
{
PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
PVOID PoolToFree;
LONG OldValue, NewValue;
POB_SD_CACHE_LIST Chain;
PETHREAD CurrentThread;
ULONG Slot;
SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
//
// First see if its possible to do a non-zero transition lock free.
//
OldValue = SecurityDescriptorHeader->RefCount;
//
// If the old value is equal to the decrement then we will be the deleter of this block. We need the lock for that
//
while (OldValue != (LONG) Count) {
NewValue = InterlockedCompareExchange ((PLONG)&SecurityDescriptorHeader->RefCount, OldValue - Count, OldValue);
if (NewValue == OldValue) {
return;
}
OldValue = NewValue;
}
//
// Lock the security descriptor cache and get a pointer
// to the security descriptor header
//
Slot = SecurityDescriptorHeader->FullHash % SECURITY_DESCRIPTOR_CACHE_ENTRIES;
Chain = &ObsSecurityDescriptorCache[Slot];
CurrentThread = PsGetCurrentThread ();
KeEnterCriticalRegionThread (&CurrentThread->Tcb);
ExAcquirePushLockExclusive (&Chain->PushLock);
//
// Do some debug work
//
ObPrint( SHOW_REFERENCES, ("Dereferencing SecurityDescriptor %x, hash %lx, refcount = %d \n", SecurityDescriptor,
SecurityDescriptorHeader->FullHash,
SecurityDescriptorHeader->RefCount));
ASSERT(SecurityDescriptorHeader->RefCount != 0);
//
// Decrement the ref count and if it is now zero then
// we can completely remove this entry from the cache
//
if (InterlockedExchangeAdd ((PLONG)&SecurityDescriptorHeader->RefCount, -(LONG)Count) == (LONG)Count) {
PoolToFree = ObpDestroySecurityDescriptorHeader (SecurityDescriptorHeader);
//
// Unlock the security descriptor cache and free the pool
//
ExReleasePushLockExclusive (&Chain->PushLock);
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
ExFreePool (PoolToFree);
} else {
//
// Unlock the security descriptor cache and return to our caller
//
ExReleasePushLockExclusive (&Chain->PushLock);
KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
}
}
PVOID
ObpDestroySecurityDescriptorHeader (
IN PSECURITY_DESCRIPTOR_HEADER Header
)
/*++
Routine Description:
Frees a cached security descriptor and unlinks it from the chain.
Arguments:
Header - Pointer to a security descriptor header (cached security
descriptor)
Return Value:
None.
--*/
{
ASSERT ( Header->RefCount == 0 );
#if OB_DIAGNOSTICS_ENABLED
InterlockedDecrement (&ObsTotalCacheEntries);
#endif
ObPrint( SHOW_STATISTICS, ("ObsTotalCacheEntries = %d \n",ObsTotalCacheEntries));
//
// Unlink the cached security descriptor from its linked list
//
RemoveEntryList (&Header->Link);
ObPrint( SHOW_HEADER_FREE, ("Freeing memory at %x \n",Header));
//
// Now return the cached descriptor to our caller to free
//
return Header;
}
BOOLEAN
ObpCompareSecurityDescriptors (
IN PSECURITY_DESCRIPTOR SD1,
IN ULONG Length1,
IN PSECURITY_DESCRIPTOR SD2
)
/*++
Routine Description:
Performs a byte by byte comparison of two self relative security
descriptors to determine if they are identical.
Arguments:
SD1, SD2 - Security descriptors to be compared.
Length1 - Length of SD1
Return Value:
TRUE - They are the same.
FALSE - They are different.
--*/
{
ULONG Length2;
//
// Calculating the length is pretty fast, see if we
// can get away with doing only that.
//
ASSERT (Length1 == RtlLengthSecurityDescriptor ( SD1 ));
Length2 = RtlLengthSecurityDescriptor ( SD2 );
if (Length1 != Length2) {
return( FALSE );
}
return (BOOLEAN)RtlEqualMemory ( SD1, SD2, Length1 );
}