Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1046 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. cmsecache.c
  5. Abstract:
  6. This module implements the security cache.
  7. Author:
  8. Dragos C. Sambotin (dragoss) 09-Sep-1999
  9. --*/
  10. #include "cmp.h"
  11. #define SECURITY_CACHE_GROW_INCREMENTS 0x10
  12. #ifdef HIVE_SECURITY_STATS
  13. ULONG
  14. CmpCheckForSecurityDuplicates(
  15. IN OUT PCMHIVE CmHive
  16. );
  17. #endif
  18. BOOLEAN
  19. CmpFindMatchingDescriptorCell(
  20. IN PCMHIVE CmHive,
  21. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  22. IN ULONG Type,
  23. OUT PHCELL_INDEX MatchingCell,
  24. OUT OPTIONAL PCM_KEY_SECURITY_CACHE *CachedSecurityPointer
  25. );
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text(PAGE,CmpSecConvKey)
  28. #pragma alloc_text(PAGE,CmpInitSecurityCache)
  29. #pragma alloc_text(PAGE,CmpDestroySecurityCache)
  30. #pragma alloc_text(PAGE,CmpRebuildSecurityCache)
  31. #pragma alloc_text(PAGE,CmpAddSecurityCellToCache)
  32. #pragma alloc_text(PAGE,CmpFindSecurityCellCacheIndex)
  33. #pragma alloc_text(PAGE,CmpAdjustSecurityCacheSize)
  34. #pragma alloc_text(PAGE,CmpRemoveFromSecurityCache)
  35. #pragma alloc_text(PAGE,CmpFindMatchingDescriptorCell)
  36. #pragma alloc_text(PAGE,CmpAssignSecurityToKcb)
  37. #ifdef HIVE_SECURITY_STATS
  38. #pragma alloc_text(PAGE,CmpCheckForSecurityDuplicates)
  39. #endif
  40. #pragma alloc_text(PAGE,CmpBuildSecurityCellMappingArray)
  41. #endif
  42. ULONG
  43. CmpSecConvKey(
  44. IN ULONG DescriptorLength,
  45. IN PULONG Descriptor
  46. )
  47. /*++
  48. Routine Description:
  49. Computes the ConvKey for the given security descriptor.
  50. The algorithm is stollen from the NTFS security hash.
  51. (it was proven to be efficient there; why shouldn't do the same ?)
  52. For speed in the hash, we consider the security descriptor as an array
  53. of ULONGs. The fragment at the end that is ignored should not affect
  54. the collision nature of this hash.
  55. Arguments:
  56. DescriptorLength - length (in bytes) of the sd
  57. Descriptor - actual sd to cache
  58. Return Value:
  59. ConvKey
  60. Note:
  61. We may want to convert this to a macro
  62. --*/
  63. {
  64. ULONG Count;
  65. ULONG Hash = 0;
  66. PAGED_CODE();
  67. Count = DescriptorLength / 4;
  68. while (Count--) {
  69. Hash = ((Hash << 3) | (Hash >> (32-3))) + *Descriptor++;
  70. }
  71. return Hash;
  72. }
  73. VOID
  74. CmpInitSecurityCache(
  75. IN OUT PCMHIVE CmHive
  76. )
  77. {
  78. ULONG i;
  79. PAGED_CODE();
  80. CmHive->SecurityCache = NULL;
  81. CmHive->SecurityCacheSize = 0;
  82. CmHive->SecurityCount = 0;
  83. CmHive->SecurityHitHint = -1; // no hint
  84. for( i=0;i<CmpSecHashTableSize;i++) {
  85. InitializeListHead(&(CmHive->SecurityHash[i]));
  86. }
  87. }
  88. NTSTATUS
  89. CmpAddSecurityCellToCache (
  90. IN OUT PCMHIVE CmHive,
  91. IN HCELL_INDEX SecurityCell,
  92. IN BOOLEAN BuildUp
  93. )
  94. /*++
  95. Routine Description:
  96. This routine adds the specified security cell to the cache of the
  97. specified hive. It takes care of cache allocation (grow) as well.
  98. At build up time, cache size grows with a PAGE_SIZE, to avoid memory
  99. fragmentation. After the table is builded, it's size is adjusted (most
  100. of the hives never add new security cells). Then, at run-time, the size
  101. grows with 16 entries at a time (same reason)
  102. The cache is ordered by the cell's index, so we can do a binary search on
  103. cells retrieval.
  104. Arguments:
  105. CmHive - the hive to which the security cell belongs
  106. SecurityCell - the security cell to be added to the cache
  107. BuildUp - specifies that this is build up time
  108. Return Value:
  109. NTSTATUS - STATUS_SUCCESS if the operation is successful and an
  110. appropriate error status otherwise (i.e STATUS_INSUFFICIENT_RESOURCES).
  111. Note:
  112. If the security cell is already IN the cache; this function will return TRUE.
  113. --*/
  114. {
  115. ULONG Index;
  116. ULONG Size;
  117. PCM_KEY_SECURITY Security;
  118. PCM_KEY_SECURITY_CACHE SecurityCached;
  119. PAGED_CODE();
  120. if( CmpFindSecurityCellCacheIndex (CmHive,SecurityCell,&Index) == TRUE ) {
  121. //
  122. // cell already exist in the cache; return;
  123. //
  124. return STATUS_SUCCESS;
  125. }
  126. //
  127. // if this fails, we're doomed !
  128. //
  129. ASSERT( (PAGE_SIZE % sizeof(CM_KEY_SECURITY_CACHE_ENTRY)) == 0 );
  130. //
  131. // check if the cache can accomodate a new cell
  132. //
  133. if( CmHive->SecurityCount == CmHive->SecurityCacheSize ) {
  134. //
  135. // We're at the limit with the cache; we need to extend it by a page
  136. //
  137. // OBS: this takes care of the first allocation too, as SecurityCount
  138. // and SecurityCacheSize are both initialized with 0
  139. //
  140. PCM_KEY_SECURITY_CACHE_ENTRY Temp;
  141. // store the actual buffer
  142. Temp = CmHive->SecurityCache;
  143. //
  144. // compute the new size and allocate a new buffer
  145. //
  146. if( BuildUp == TRUE ) {
  147. //
  148. // We are building up the cache; grow the table in page increments
  149. //
  150. ASSERT( ((CmHive->SecurityCacheSize * sizeof(CM_KEY_SECURITY_CACHE_ENTRY)) % PAGE_SIZE) == 0 );
  151. CmHive->SecurityCacheSize += (PAGE_SIZE / sizeof(CM_KEY_SECURITY_CACHE_ENTRY));
  152. } else {
  153. //
  154. // normal case (running time); a new security cell is added; grow the
  155. // table with a fixed number of increments (to avoid fragmentation, in
  156. // case of an Office install :-) )
  157. //
  158. CmHive->SecurityCacheSize += SECURITY_CACHE_GROW_INCREMENTS;
  159. }
  160. CmHive->SecurityCache = ExAllocatePoolWithTag(PagedPool, CmHive->SecurityCacheSize * sizeof(CM_KEY_SECURITY_CACHE_ENTRY),CM_SECCACHE_TAG|PROTECTED_POOL);
  161. if( CmHive->SecurityCache == NULL ) {
  162. //
  163. // bad luck; bail out
  164. //
  165. CmHive->SecurityCache = Temp;
  166. CmHive->SecurityCacheSize = CmHive->SecurityCount;
  167. return STATUS_INSUFFICIENT_RESOURCES;
  168. }
  169. //
  170. // copy existing data in the new location and free the old buffer
  171. //
  172. RtlCopyMemory(CmHive->SecurityCache,Temp,CmHive->SecurityCount*sizeof(CM_KEY_SECURITY_CACHE_ENTRY));
  173. if( Temp != NULL ) {
  174. ExFreePoolWithTag(Temp, CM_SECCACHE_TAG|PROTECTED_POOL );
  175. } else {
  176. ASSERT( CmHive->SecurityCount == 0 );
  177. }
  178. }
  179. //
  180. // try first to get the security cell from the hive; if this fails, there is no point to go on
  181. //
  182. Security = (PCM_KEY_SECURITY)HvGetCell(&(CmHive->Hive),SecurityCell);
  183. if( Security == NULL ){
  184. //
  185. // we failed to map the view containing this cell; bail out
  186. //
  187. return STATUS_INSUFFICIENT_RESOURCES;
  188. }
  189. //
  190. // compute the size for the cached security structure
  191. //
  192. Size = FIELD_OFFSET(CM_KEY_SECURITY_CACHE,Descriptor) + Security->DescriptorLength;
  193. //
  194. // think forward: allocate and initialize a copy for the security cell, in order to store it in the cache
  195. //
  196. SecurityCached = (PCM_KEY_SECURITY_CACHE)ExAllocatePoolWithTag(PagedPool,Size,CM_SECCACHE_TAG|PROTECTED_POOL);
  197. if(SecurityCached == NULL) {
  198. //
  199. // bad luck; bail out
  200. //
  201. HvReleaseCell(&(CmHive->Hive),SecurityCell);
  202. return STATUS_INSUFFICIENT_RESOURCES;
  203. }
  204. //
  205. // from now on, nothing can go wrong !
  206. //
  207. RtlCopyMemory(&(SecurityCached->Descriptor),&(Security->Descriptor),Security->DescriptorLength);
  208. SecurityCached->Cell = SecurityCell;
  209. SecurityCached->DescriptorLength = Security->DescriptorLength;
  210. //
  211. // now add this to the hash table
  212. //
  213. SecurityCached->ConvKey = CmpSecConvKey(Security->DescriptorLength,(PULONG)(&(Security->Descriptor)));
  214. // add it to the end of the list with this conv key
  215. InsertTailList( &(CmHive->SecurityHash[SecurityCached->ConvKey % CmpSecHashTableSize]),
  216. &(SecurityCached->List)
  217. );
  218. HvReleaseCell(&(CmHive->Hive),SecurityCell);
  219. //
  220. // At this point we are sure we have space for at least one more entry
  221. // Move data to make room for the new entry
  222. //
  223. if( Index < CmHive->SecurityCount ) {
  224. //
  225. // RtlMoveMemory will take care of the overlapping problem
  226. //
  227. RtlMoveMemory( ((PUCHAR)CmHive->SecurityCache) + (Index+1)*sizeof(CM_KEY_SECURITY_CACHE_ENTRY), // destination
  228. ((PUCHAR)CmHive->SecurityCache) + Index*sizeof(CM_KEY_SECURITY_CACHE_ENTRY), // source
  229. (CmHive->SecurityCount - Index)*sizeof(CM_KEY_SECURITY_CACHE_ENTRY) // size
  230. );
  231. }
  232. //
  233. // setup the new entry
  234. //
  235. CmHive->SecurityCache[Index].Cell = SecurityCell;
  236. CmHive->SecurityCache[Index].CachedSecurity = SecurityCached;
  237. // update the count
  238. CmHive->SecurityCount++;
  239. return STATUS_SUCCESS;
  240. }
  241. BOOLEAN
  242. CmpFindSecurityCellCacheIndex (
  243. IN PCMHIVE CmHive,
  244. IN HCELL_INDEX SecurityCell,
  245. OUT PULONG Index
  246. )
  247. /*++
  248. Routine Description:
  249. Search (binary) for the specified cellindex in the security cache.
  250. Returns the index of the cache entry where the cell is cached or
  251. it should be added
  252. Arguments:
  253. CmHive - the hive to which the security cell belongs
  254. SecurityCell - the security cell to search for
  255. Index - out param to pass the index at which the cell is (or it should be)
  256. Return Value:
  257. TRUE - the cell was found (at *Index)
  258. FALSE - the cell is not in the cache (it should be added at *Index)
  259. --*/
  260. {
  261. ULONG High;
  262. ULONG Low;
  263. ULONG Current;
  264. USHORT State = 0; // state of the operation: 0 - normal binary search
  265. // 1 - last low
  266. // 2 - last high
  267. LONG Result;
  268. LONG Tmp1,Tmp2;
  269. PAGED_CODE();
  270. if( CmHive->SecurityCount == 0 ) {
  271. //
  272. // there is no cell in the security cache
  273. //
  274. *Index = 0;
  275. return FALSE;
  276. }
  277. // sanity asserts
  278. ASSERT( CmHive->SecurityCount <= CmHive->SecurityCacheSize );
  279. ASSERT( CmHive->SecurityCache != NULL );
  280. High = CmHive->SecurityCount - 1;
  281. Low = 0;
  282. if( (CmHive->SecurityHitHint >= 0) && ( (ULONG)CmHive->SecurityHitHint <= High) ) {
  283. //
  284. // try the last search
  285. //
  286. Current = CmHive->SecurityHitHint;
  287. } else {
  288. Current = High/2;
  289. }
  290. // sign adjustment
  291. Tmp1 = SecurityCell & ~HCELL_TYPE_MASK;
  292. if( SecurityCell & HCELL_TYPE_MASK ) {
  293. Tmp1 = -Tmp1;
  294. }
  295. while( TRUE ) {
  296. Tmp2 = CmHive->SecurityCache[Current].Cell & ~HCELL_TYPE_MASK;
  297. // sign adjustment
  298. if( CmHive->SecurityCache[Current].Cell & HCELL_TYPE_MASK ) {
  299. Tmp2 = -Tmp2;
  300. }
  301. Result = Tmp1 - Tmp2;
  302. if (Result == 0) {
  303. //
  304. // Success, return data to caller and exit
  305. //
  306. *Index = Current;
  307. //
  308. // we have a hit! update the count and exit
  309. //
  310. CmHive->SecurityHitHint = Current;
  311. return TRUE;
  312. }
  313. //
  314. // compute the next index to try
  315. //
  316. switch(State) {
  317. case 0:
  318. //
  319. // normal binary search state
  320. //
  321. if( Result < 0 ) {
  322. High = Current;
  323. } else {
  324. Low = Current;
  325. }
  326. if ((High - Low) <= 1) {
  327. //
  328. // advance to the new state
  329. //
  330. Current = Low;
  331. State = 1;
  332. } else {
  333. Current = Low + ( (High-Low) / 2 );
  334. }
  335. break;
  336. case 1:
  337. //
  338. // last low state
  339. //
  340. // this should be true
  341. ASSERT( Current == Low );
  342. if (Result < 0) {
  343. //
  344. // does not exist, under
  345. //
  346. *Index = Current;
  347. return FALSE;
  348. } else if( Low == High ) {
  349. //
  350. // low and high are identical; but current is bigger than them; insert after
  351. //
  352. *Index = Current + 1;
  353. return FALSE;
  354. } else {
  355. //
  356. // advance to the new state; i.e. look at high
  357. //
  358. State = 2;
  359. Current = High;
  360. }
  361. break;
  362. case 2:
  363. //
  364. // last high state; if we got here, High = Low +1 and Current == High
  365. //
  366. ASSERT( Current == High);
  367. ASSERT( High == (Low + 1) );
  368. if( Result < 0 ) {
  369. //
  370. // under High, but above Low; we should insert it here
  371. //
  372. *Index = Current;
  373. return FALSE;
  374. } else {
  375. //
  376. // above High;
  377. //
  378. *Index = Current + 1;
  379. return FALSE;
  380. }
  381. break;
  382. default:
  383. ASSERT( FALSE );
  384. break;
  385. }
  386. }
  387. //
  388. // we shouldn't get here !!!
  389. //
  390. ASSERT( FALSE );
  391. return FALSE;
  392. }
  393. BOOLEAN
  394. CmpAdjustSecurityCacheSize (
  395. IN PCMHIVE CmHive
  396. )
  397. /*++
  398. Routine Description:
  399. Adjust the scusrity cache size for the specified hive. This function
  400. should be called after all the security cells for the hive were cached,
  401. in order to give back extra memory used in the process.
  402. Arguments:
  403. CmHive - the hive to which the security cell belongs
  404. Return Value:
  405. TRUE - success
  406. FALSE - failure - the size remains the same
  407. --*/
  408. {
  409. PCM_KEY_SECURITY_CACHE_ENTRY Buffer;
  410. PAGED_CODE();
  411. if( CmHive->SecurityCount < CmHive->SecurityCacheSize ) {
  412. //
  413. // cache size is bigger than what we need; there is a good chance
  414. // nobody will ever add new security cells to this hive, so go on
  415. // and free the extra space
  416. //
  417. //
  418. // allocate a new buffer with the exact size we need
  419. //
  420. Buffer = ExAllocatePoolWithTag(PagedPool, CmHive->SecurityCount * sizeof(CM_KEY_SECURITY_CACHE_ENTRY),CM_SECCACHE_TAG|PROTECTED_POOL);
  421. if( Buffer == NULL ) {
  422. //
  423. // the system is low on resources; leave the cache as it is
  424. //
  425. return FALSE;
  426. }
  427. //
  428. // copy significant data inot the new buffer
  429. //
  430. RtlCopyMemory(Buffer,CmHive->SecurityCache,CmHive->SecurityCount*sizeof(CM_KEY_SECURITY_CACHE_ENTRY));
  431. //
  432. // free the old buffer and update cache members
  433. //
  434. ExFreePoolWithTag(CmHive->SecurityCache, CM_SECCACHE_TAG|PROTECTED_POOL );
  435. CmHive->SecurityCache = Buffer;
  436. CmHive->SecurityCacheSize = CmHive->SecurityCount;
  437. }
  438. return TRUE;
  439. }
  440. VOID
  441. CmpRemoveFromSecurityCache (
  442. IN OUT PCMHIVE CmHive,
  443. IN HCELL_INDEX SecurityCell
  444. )
  445. /*++
  446. Routine Description:
  447. Removes the specified security cell from the security cache.
  448. (only if present !)
  449. For performance (and memory fragmentation) reasons, it does not
  450. change (shrink) the cache size.
  451. Arguments:
  452. CmHive - the hive to which the security cell belongs
  453. SecurityCell - the security cell to be removed from the cache
  454. Return Value:
  455. <none>
  456. --*/
  457. {
  458. ULONG Index;
  459. PAGED_CODE();
  460. if( CmpFindSecurityCellCacheIndex (CmHive,SecurityCell,&Index) == FALSE ) {
  461. //
  462. // cell is not in the cache
  463. //
  464. return;
  465. }
  466. ASSERT( CmHive->SecurityCache[Index].Cell == SecurityCell );
  467. ASSERT( CmHive->SecurityCache[Index].CachedSecurity->Cell == SecurityCell );
  468. //
  469. // remove the cached structure from the hash
  470. //
  471. CmpRemoveEntryList(&(CmHive->SecurityCache[Index].CachedSecurity->List));
  472. //
  473. // free up the cached security cell;
  474. //
  475. ExFreePoolWithTag(CmHive->SecurityCache[Index].CachedSecurity, CM_SECCACHE_TAG|PROTECTED_POOL );
  476. //
  477. // move memory to reflect the new size, and update the cache count
  478. //
  479. RtlMoveMemory( ((PUCHAR)CmHive->SecurityCache) + Index*sizeof(CM_KEY_SECURITY_CACHE_ENTRY), // destination
  480. ((PUCHAR)CmHive->SecurityCache) + (Index+1)*sizeof(CM_KEY_SECURITY_CACHE_ENTRY), // source
  481. (CmHive->SecurityCount - Index - 1)*sizeof(CM_KEY_SECURITY_CACHE_ENTRY) // size
  482. );
  483. CmHive->SecurityCount--;
  484. }
  485. VOID
  486. CmpDestroySecurityCache (
  487. IN OUT PCMHIVE CmHive
  488. )
  489. /*++
  490. Routine Description:
  491. Frees up all the cached security cells and the cache itself
  492. Arguments:
  493. CmHive - the hive to which the security cell belongs
  494. Return Value:
  495. <none>
  496. --*/
  497. {
  498. ULONG i;
  499. PAGED_CODE();
  500. for( i=0;i<CmHive->SecurityCount;i++) {
  501. CmpRemoveEntryList(&(CmHive->SecurityCache[i].CachedSecurity->List));
  502. ExFreePoolWithTag(CmHive->SecurityCache[i].CachedSecurity, CM_SECCACHE_TAG|PROTECTED_POOL );
  503. }
  504. if( CmHive->SecurityCount != 0 ) {
  505. ASSERT( CmHive->SecurityCache != NULL );
  506. ExFreePoolWithTag(CmHive->SecurityCache, CM_SECCACHE_TAG|PROTECTED_POOL );
  507. }
  508. CmHive->SecurityCache = NULL;
  509. CmHive->SecurityCacheSize = CmHive->SecurityCount = 0;
  510. }
  511. BOOLEAN
  512. CmpRebuildSecurityCache(
  513. IN OUT PCMHIVE CmHive
  514. )
  515. /*++
  516. Routine Description:
  517. Rebuilds the security cache by reiterating all security cells
  518. and adding them to the cache; this routine is intended for hive
  519. refresh operations
  520. Arguments:
  521. CmHive - the hive to which the security cell belongs
  522. Return Value:
  523. TRUE or FALSE
  524. --*/
  525. {
  526. PCM_KEY_NODE RootNode;
  527. PCM_KEY_SECURITY SecurityCell;
  528. HCELL_INDEX ListAnchor;
  529. HCELL_INDEX NextCell;
  530. HCELL_INDEX LastCell;
  531. PHHIVE Hive;
  532. PRELEASE_CELL_ROUTINE ReleaseCellRoutine;
  533. BOOLEAN Result = TRUE;
  534. PAGED_CODE();
  535. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  536. //
  537. // avoid extra work
  538. //
  539. Hive = &(CmHive->Hive);
  540. ReleaseCellRoutine = Hive->ReleaseCellRoutine;
  541. Hive->ReleaseCellRoutine = NULL;
  542. //
  543. // destroy existing cache and set up an empty one
  544. //
  545. CmpDestroySecurityCache(CmHive);
  546. CmpInitSecurityCache(CmHive);
  547. if (!HvIsCellAllocated(Hive,Hive->BaseBlock->RootCell)) {
  548. //
  549. // root cell HCELL_INDEX is bogus
  550. //
  551. Result = FALSE;
  552. goto JustReturn;
  553. }
  554. RootNode = (PCM_KEY_NODE) HvGetCell(Hive, Hive->BaseBlock->RootCell);
  555. if( RootNode == NULL ) {
  556. //
  557. // we couldn't map a view for the bin containing this cell
  558. //
  559. Result = FALSE;
  560. goto JustReturn;
  561. }
  562. ListAnchor = NextCell = RootNode->Security;
  563. do {
  564. if (!HvIsCellAllocated(Hive, NextCell)) {
  565. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CM: CmpRebuildSecurityCache\n"));
  566. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," NextCell: %08lx is invalid HCELL_INDEX\n",NextCell));
  567. Result = FALSE;
  568. goto JustReturn;
  569. }
  570. SecurityCell = (PCM_KEY_SECURITY) HvGetCell(Hive, NextCell);
  571. if( SecurityCell == NULL ) {
  572. //
  573. // we couldn't map a view for the bin containing this cell
  574. //
  575. Result = FALSE;
  576. goto JustReturn;
  577. }
  578. if (NextCell != ListAnchor) {
  579. //
  580. // Check to make sure that our Blink points to where we just
  581. // came from.
  582. //
  583. if (SecurityCell->Blink != LastCell) {
  584. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," Invalid Blink (%ld) on security cell %ld\n",SecurityCell->Blink, NextCell));
  585. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," should point to %ld\n", LastCell));
  586. Result = FALSE;
  587. goto JustReturn;
  588. }
  589. }
  590. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpValidSD: SD shared by %d nodes\n",SecurityCell->ReferenceCount));
  591. if (!SeValidSecurityDescriptor(SecurityCell->DescriptorLength, &SecurityCell->Descriptor)) {
  592. #if DBG
  593. CmpDumpSecurityDescriptor(&SecurityCell->Descriptor,"INVALID DESCRIPTOR");
  594. #endif
  595. Result = FALSE;
  596. goto JustReturn;
  597. }
  598. if( !NT_SUCCESS(CmpAddSecurityCellToCache ( CmHive,NextCell,TRUE) ) ) {
  599. Result = FALSE;
  600. goto JustReturn;
  601. }
  602. LastCell = NextCell;
  603. NextCell = SecurityCell->Flink;
  604. } while ( NextCell != ListAnchor );
  605. //
  606. // adjust the size of the cache in case we allocated too much
  607. //
  608. CmpAdjustSecurityCacheSize ( (PCMHIVE)Hive );
  609. JustReturn:
  610. Hive->ReleaseCellRoutine = ReleaseCellRoutine;
  611. return Result;
  612. }
  613. BOOLEAN
  614. CmpFindMatchingDescriptorCell(
  615. IN PCMHIVE CmHive,
  616. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  617. IN ULONG Type,
  618. OUT PHCELL_INDEX MatchingCell,
  619. OUT OPTIONAL PCM_KEY_SECURITY_CACHE *CachedSecurityPointer
  620. )
  621. /*++
  622. Routine Description:
  623. This routine attempts to find a security descriptor in the hive that
  624. is identical to the one passed in. If it finds one, it returns its
  625. cell index.
  626. Obsolete:
  627. Currently, this routine checks the security descriptors of the parent
  628. and siblings of the node to find a match.
  629. New:
  630. It looks for the sd in the security cache for this hive. This will
  631. eliminate duplicates and make the search process faster.
  632. Arguments:
  633. CmHive - Supplies a pointer to the hive control structure for the node.
  634. Needed to get access to the cache
  635. SecurityDescriptor - Supplies the cooked security descriptor which
  636. should be searched for.
  637. Type - Indicates whether the Security Descriptor that matches must
  638. be in Stable or Volatile store
  639. MatchingCell - Returns the cell index of a security cell whose
  640. security descriptor is identical to SecurityDescriptor.
  641. Valid only if TRUE is returned.
  642. CachedSecurityPointer - pointer to the cached security (for update reasons)
  643. Return Value:
  644. TRUE - Matching security descriptor found. MatchingCell returns the
  645. cell index of the matching security descriptor.
  646. FALSE - No matching security descriptor found. MatchingCell is invalid.
  647. --*/
  648. {
  649. ULONG DescriptorLength;
  650. ULONG ConvKey;
  651. PLIST_ENTRY ListAnchor;
  652. PLIST_ENTRY Current;
  653. PCM_KEY_SECURITY_CACHE CachedSecurity;
  654. PAGED_CODE();
  655. DescriptorLength = RtlLengthSecurityDescriptor(SecurityDescriptor);
  656. //
  657. // calculate the conv key
  658. //
  659. ConvKey = CmpSecConvKey(DescriptorLength,(PULONG)SecurityDescriptor);
  660. ListAnchor = &(CmHive->SecurityHash[ConvKey % CmpSecHashTableSize]);
  661. if( IsListEmpty(ListAnchor) == TRUE ) {
  662. return FALSE;
  663. }
  664. //
  665. // iterate through the list of colisions for this convkey
  666. // start with teh first element in list
  667. //
  668. Current = (PLIST_ENTRY)(ListAnchor->Flink);
  669. while( Current != ListAnchor ){
  670. //
  671. // get the current cached security
  672. //
  673. CachedSecurity = CONTAINING_RECORD(Current,
  674. CM_KEY_SECURITY_CACHE,
  675. List);
  676. //
  677. // see if it matches with the given descriptor;
  678. //
  679. if( (CachedSecurity->ConvKey == ConvKey) && // same convkey
  680. (Type == HvGetCellType(CachedSecurity->Cell)) && // same cell type
  681. (DescriptorLength == CachedSecurity->DescriptorLength) && // same length
  682. (RtlEqualMemory(SecurityDescriptor, // and, finally, bit-wise identical
  683. &(CachedSecurity->Descriptor),
  684. DescriptorLength))
  685. ) {
  686. //
  687. // we have found a match
  688. //
  689. *MatchingCell = CachedSecurity->Cell;
  690. if (ARGUMENT_PRESENT(CachedSecurityPointer)) {
  691. *CachedSecurityPointer = CachedSecurity;
  692. }
  693. return TRUE;
  694. }
  695. //
  696. // advance to the next element
  697. //
  698. Current = (PLIST_ENTRY)(Current->Flink);
  699. }
  700. // sorry, no match
  701. return FALSE;
  702. }
  703. VOID
  704. CmpAssignSecurityToKcb(
  705. IN PCM_KEY_CONTROL_BLOCK Kcb,
  706. IN HCELL_INDEX SecurityCell
  707. )
  708. /*++
  709. Routine Description:
  710. Establishes the connection between the KCB and the cached security
  711. descriptor.
  712. As most of the time this is called after the security cell has been
  713. linked to the Key Node, and because the binary search starts with
  714. the last cell looked up, we will not hit a performance impact here.
  715. Arguments:
  716. Kcb - the KCb to which this security cell needs to be attached
  717. SecurityCell - Security cell for the kcb
  718. Return Value:
  719. NONE; bugchecks on error
  720. --*/
  721. {
  722. ULONG Index;
  723. PCMHIVE CmHive;
  724. PAGED_CODE();
  725. if( SecurityCell == HCELL_NIL ) {
  726. Kcb->CachedSecurity = NULL;
  727. return;
  728. }
  729. CmHive = (PCMHIVE)(Kcb->KeyHive);
  730. //
  731. // get the security descriptor from cache
  732. //
  733. if( CmpFindSecurityCellCacheIndex (CmHive,SecurityCell,&Index) == FALSE ) {
  734. Kcb->CachedSecurity = NULL;
  735. //
  736. // we are doomed !!!
  737. //
  738. CM_BUGCHECK( REGISTRY_ERROR,BAD_SECURITY_CACHE,1,Kcb,SecurityCell);
  739. }
  740. //
  741. // success; link the cached security to this KCB
  742. //
  743. Kcb->CachedSecurity = CmHive->SecurityCache[Index].CachedSecurity;
  744. }
  745. #ifdef HIVE_SECURITY_STATS
  746. ULONG
  747. CmpCheckForSecurityDuplicates(
  748. IN OUT PCMHIVE CmHive
  749. )
  750. /*++
  751. Routine Description:
  752. Iterates through the security cache for the specified hive and detects
  753. if there are any security descriptors which are duplicated
  754. Arguments:
  755. CmHive - the hive in question
  756. Return Value:
  757. number of duplicates (it should be 0)
  758. --*/
  759. {
  760. ULONG i,j,Duplicates = 0;
  761. PCM_KEY_SECURITY_CACHE CachedSecurity1,CachedSecurity2;
  762. HCELL_INDEX Cell1,Cell2;
  763. PAGED_CODE();
  764. for( i=0;i<CmHive->SecurityCount - 1;i++) {
  765. CachedSecurity1 = CmHive->SecurityCache[i].CachedSecurity;
  766. Cell1 = CmHive->SecurityCache[i].Cell;
  767. ASSERT( Cell1 == CachedSecurity1->Cell );
  768. for( j=i+1;j<CmHive->SecurityCount;j++) {
  769. CachedSecurity2 = CmHive->SecurityCache[j].CachedSecurity;
  770. Cell2 = CmHive->SecurityCache[j].Cell;
  771. ASSERT( Cell2 == CachedSecurity2->Cell );
  772. if ((CachedSecurity1->DescriptorLength == CachedSecurity2->DescriptorLength) &&
  773. (HvGetCellType(Cell1) == HvGetCellType(Cell2)) &&
  774. (RtlEqualMemory(&(CachedSecurity1->Descriptor),
  775. &(CachedSecurity2->Descriptor),
  776. CachedSecurity1->DescriptorLength))) {
  777. ASSERT( CachedSecurity1->ConvKey == CachedSecurity2->ConvKey );
  778. //
  779. // we've found a duplicate cell;
  780. //
  781. #ifndef _CM_LDR_
  782. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Duplicate security cell found in Hive %p Cell1=%8lx Cell2 = %8lx\n",(&(CmHive->Hive)),Cell1,Cell2);
  783. #endif //_CM_LDR_
  784. Duplicates++;
  785. break;
  786. }
  787. }
  788. }
  789. return Duplicates;
  790. }
  791. #endif
  792. BOOLEAN
  793. CmpBuildSecurityCellMappingArray(
  794. IN PCMHIVE CmHive
  795. )
  796. /*++
  797. Routine Description:
  798. Iterates through the security cache for the specified hive and
  799. build the array of mappings.
  800. Arguments:
  801. CmHive - the hive in question
  802. Return Value:
  803. TRUE/FALSE
  804. --*/
  805. {
  806. ULONG i;
  807. PAGED_CODE();
  808. ASSERT( CmHive->CellRemapArray == NULL );
  809. CmHive->CellRemapArray = ExAllocatePool(PagedPool,sizeof(CM_CELL_REMAP_BLOCK)*CmHive->SecurityCount);
  810. if( CmHive->CellRemapArray == NULL ) {
  811. return FALSE;
  812. }
  813. for( i=0;i<CmHive->SecurityCount;i++) {
  814. CmHive->CellRemapArray[i].OldCell = CmHive->SecurityCache[i].Cell;
  815. if( HvGetCellType(CmHive->SecurityCache[i].Cell) == (ULONG)Volatile ) {
  816. //
  817. // we preserve volatile cells
  818. //
  819. CmHive->CellRemapArray[i].NewCell = CmHive->SecurityCache[i].Cell;
  820. } else {
  821. CmHive->CellRemapArray[i].NewCell = HCELL_NIL;
  822. }
  823. }
  824. return TRUE;
  825. }