VOID CmpCleanUpKcbValueCache( PCM_KEY_CONTROL_BLOCK KeyControlBlock ) /*++ Routine Description: Clean up cached value/data that are associated to this key. Arguments: KeyControlBlock - pointer to a key control block. Return Value: NONE. --*/ { ULONG i; PULONG_PTR CachedList; PCELL_DATA pcell; ULONG realsize; BOOLEAN small; if (CMP_IS_CELL_CACHED(KeyControlBlock->ValueCache.ValueList)) { CachedList = (PULONG_PTR) CMP_GET_CACHED_CELLDATA(KeyControlBlock->ValueCache.ValueList); for (i = 0; i < KeyControlBlock->ValueCache.Count; i++) { if (CMP_IS_CELL_CACHED(CachedList[i])) { // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList[i]) ); ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(CachedList[i])); } } // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList) ); ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); // Mark the ValueList as NULL KeyControlBlock->ValueCache.ValueList = HCELL_NIL; } else if (KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) { // // This is a symbolic link key with symbolic name resolved. // Dereference to its real kcb and clear the bit. // if ((KeyControlBlock->ValueCache.RealKcb->RefCount == 1) && !(KeyControlBlock->ValueCache.RealKcb->Delete)) { KeyControlBlock->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; } CmpDereferenceKeyControlBlockWithLock(KeyControlBlock->ValueCache.RealKcb); KeyControlBlock->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; } }
VOID NTAPI CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb) { PULONG_PTR CachedList; ULONG i; /* Sanity check */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); /* Check if the value list is cached */ if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)) { /* Get the cache list */ CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList); for (i = 0; i < Kcb->ValueCache.Count; i++) { /* Check if this cell is cached */ if (CMP_IS_CELL_CACHED(CachedList[i])) { /* Free it */ CmpFree((PVOID)CMP_GET_CACHED_CELL(CachedList[i]), 0); } } /* Now free the list */ CmpFree((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList), 0); Kcb->ValueCache.ValueList = HCELL_NIL; } else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) { /* This is a sym link, check if there's only one reference left */ if ((Kcb->ValueCache.RealKcb->RefCount == 1) && !(Kcb->ValueCache.RealKcb->Delete)) { /* Disable delay close for the KCB */ Kcb->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; } /* Dereference the KCB */ CmpDelayDerefKeyControlBlock(Kcb->ValueCache.RealKcb); Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; } }
VALUE_SEARCH_RETURN_TYPE NTAPI CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb, IN PUNICODE_STRING ValueName, IN ULONG Type, IN PVOID Data, IN ULONG DataSize) { VALUE_SEARCH_RETURN_TYPE SearchResult; PCM_KEY_NODE KeyNode; PCM_CACHED_VALUE *CachedValue; ULONG Index; PCM_KEY_VALUE Value; BOOLEAN ValueCached, BufferAllocated = FALSE; PVOID Buffer; HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL; BOOLEAN IsSmall; ULONG CompareResult; PAGED_CODE(); /* Check if this is a symlink */ if (Kcb->Flags & KEY_SYM_LINK) { /* We need the exclusive lock */ if (!(CmpIsKcbLockedExclusive(Kcb)) && !(CmpTryToConvertKcbSharedToExclusive(Kcb))) { /* We need the exclusive lock */ return SearchNeedExclusiveLock; } /* Otherwise, get the key node */ KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell); if (!KeyNode) return SearchFail; /* Cleanup the KCB cache */ CmpCleanUpKcbValueCache(Kcb); /* Sanity checks */ ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); /* Set the value cache */ Kcb->ValueCache.Count = KeyNode->ValueList.Count; Kcb->ValueCache.ValueList = KeyNode->ValueList.List; /* Release the cell */ HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell); } /* Do the search */ SearchResult = CmpFindValueByNameFromCache(Kcb, ValueName, &CachedValue, &Index, &Value, &ValueCached, &ValueCellToRelease); if (SearchResult == SearchNeedExclusiveLock) { /* We need the exclusive lock */ ASSERT(!CmpIsKcbLockedExclusive(Kcb)); ASSERT(ValueCellToRelease == HCELL_NIL); ASSERT(Value == NULL); goto Quickie; } else if (SearchResult == SearchSuccess) { /* Sanity check */ ASSERT(Value); /* First of all, check if the key size and type matches */ if ((Type == Value->Type) && (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE))) { /* Check if this is a small key */ IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; if (IsSmall) { /* Compare against the data directly */ Buffer = &Value->Data; } else { /* Do a search */ SearchResult = CmpGetValueDataFromCache(Kcb, CachedValue, (PCELL_DATA)Value, ValueCached, &Buffer, &BufferAllocated, &CellToRelease); if (SearchResult != SearchSuccess) { /* Sanity checks */ ASSERT(Buffer == NULL); ASSERT(BufferAllocated == FALSE); goto Quickie; } } /* Now check the data size */ if (DataSize) { /* Do the compare */ CompareResult = RtlCompareMemory(Buffer, Data, DataSize & ~CM_KEY_VALUE_SPECIAL_SIZE); } else { /* It's equal */ CompareResult = 0; } /* Now check if the compare wasn't equal */ if (CompareResult != DataSize) SearchResult = SearchFail; } else { /* The length or type isn't equal */ SearchResult = SearchFail; } } Quickie: /* Release the value cell */ if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease); /* Free the buffer */ if (BufferAllocated) CmpFree(Buffer, 0); /* Free the cell */ if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease); /* Return the search result */ return SearchResult; }
VALUE_SEARCH_RETURN_TYPE CmpGetValueListFromCache( IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, OUT PCELL_DATA *List, OUT BOOLEAN *IndexCached, OUT PHCELL_INDEX ValueListToRelease ) /*++ Routine Description: Get the Valve Index Array. Check if it is already cached, if not, cache it and return the cached entry. Arguments: Hive - pointer to hive control structure for hive of interest ChildList - pointer/index to the Value Index array IndexCached - Indicating whether Value Index list is cached or not. Return Value: Pointer to the Valve Index Array. NULL when we could not map view --*/ { HCELL_INDEX CellToRelease; PCACHED_CHILD_LIST ChildList; PHHIVE Hive; #ifndef _WIN64 ULONG AllocSize; PCM_CACHED_VALUE_INDEX CachedValueIndex; ULONG i; #endif ASSERT_KCB_LOCKED(KeyControlBlock); Hive = KeyControlBlock->KeyHive; ChildList = &(KeyControlBlock->ValueCache); *ValueListToRelease = HCELL_NIL; #ifndef _WIN64 *IndexCached = TRUE; if (CMP_IS_CELL_CACHED(ChildList->ValueList)) { // // The entry is already cached. // *List = CMP_GET_CACHED_CELLDATA(ChildList->ValueList); } else { // // The entry is not cached. The element contains the hive index. // ensure exclusive lock. // if( (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) && (CmpTryConvertKCBLockSharedToExclusive(KeyControlBlock) == FALSE) ) { // // need to upgrade lock to exclusive // return SearchNeedExclusiveLock; } CellToRelease = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList); *List = (PCELL_DATA) HvGetCell(Hive, CellToRelease); if( *List == NULL ) { // // we couldn't map a view for this cell // *IndexCached = FALSE; return SearchFail; } // // Allocate a PagedPool to cache the value index cell. // AllocSize = ChildList->Count * sizeof(ULONG_PTR) + FIELD_OFFSET(CM_CACHED_VALUE_INDEX, Data); CachedValueIndex = (PCM_CACHED_VALUE_INDEX) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_INDEX_TAG); if (CachedValueIndex) { CachedValueIndex->CellIndex = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList); #pragma prefast(suppress:12009, "no overflow") for (i=0; i<ChildList->Count; i++) { CachedValueIndex->Data.List[i] = (ULONG_PTR) (*List)->u.KeyList[i]; } ChildList->ValueList = CMP_MARK_CELL_CACHED(CachedValueIndex); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadOnly( CachedValueIndex ); // // Now we have the stuff cached, use the cache data. // *List = CMP_GET_CACHED_CELLDATA(ChildList->ValueList); } else { // // If the allocation fails, just do not cache it. continue. // *IndexCached = FALSE; } *ValueListToRelease = CellToRelease; } #else CellToRelease = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList); *List = (PCELL_DATA) HvGetCell(Hive, CellToRelease); *IndexCached = FALSE; if( *List == NULL ) { // // we couldn't map a view for this cell // OBS: we can drop this as we return List anyway; just for clarity // return SearchFail; } *ValueListToRelease = CellToRelease; #endif return SearchSuccess; }
VALUE_SEARCH_RETURN_TYPE CmpGetValueKeyFromCache( IN PCM_KEY_CONTROL_BLOCK KeyControlBlock, IN PCELL_DATA List, IN ULONG Index, OUT PPCM_CACHED_VALUE *ContainingList, OUT PCM_KEY_VALUE *Value, IN BOOLEAN IndexCached, OUT BOOLEAN *ValueCached, OUT PHCELL_INDEX CellToRelease ) /*++ Routine Description: Get the Valve Node. Check if it is already cached, if not but the index is cached, cache and return the value node. Arguments: Hive - pointer to hive control structure for hive of interest. List - pointer to the Value Index Array (of ULONG_PTR if cached and ULONG if non-cached) Index - Index in the Value index array ContainlingList - The address of the entry that will receive the found cached value. IndexCached - Indicate if the index list is cached. If not, everything is from the original registry data. ValueCached - Indicating whether Value is cached or not. Return Value: Pointer to the Value Node. NULL when we couldn't map a view --*/ { PULONG_PTR CachedList; ULONG AllocSize; ULONG CopySize; PCM_CACHED_VALUE CachedValue; PHHIVE Hive; *CellToRelease = HCELL_NIL; Hive = KeyControlBlock->KeyHive; *Value = NULL; if (IndexCached) { // // The index array is cached, so List is pointing to an array of ULONG_PTR. // Use CachedList. // CachedList = (PULONG_PTR) List; *ValueCached = TRUE; if (CMP_IS_CELL_CACHED(CachedList[Index])) { *Value = CMP_GET_CACHED_KEYVALUE(CachedList[Index]); *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]); } else { // // ensure exclusive lock. // if( (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) && (CmpTryConvertKCBLockSharedToExclusive(KeyControlBlock) == FALSE) ) { // // need to upgrade lock to exclusive // return SearchNeedExclusiveLock; } *Value = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]); if( *Value == NULL ) { // // we couldn't map a view for this cell // just return NULL; the caller must handle it gracefully // return SearchFail; } *CellToRelease = List->u.KeyList[Index]; // // Allocate a PagedPool to cache the value node. // CopySize = (ULONG) HvGetCellSize(Hive, *Value); AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue); CachedValue = (PCM_CACHED_VALUE) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_TAG); if (CachedValue) { // // Set the information for later use if we need to cache data as well. // if ((*Value)->Flags & VALUE_COMP_NAME) { CachedValue->HashKey = CmpComputeHashKeyForCompressedName(0,(*Value)->Name,(*Value)->NameLength); } else { UNICODE_STRING TmpStr; TmpStr.Length = (*Value)->NameLength; TmpStr.Buffer = (*Value)->Name; CachedValue->HashKey = CmpComputeHashKey(0,&TmpStr #if DBG , TRUE #endif ); } CachedValue->DataCacheType = CM_CACHE_DATA_NOT_CACHED; CachedValue->ValueKeySize = (USHORT) CopySize; RtlCopyMemory((PVOID)&(CachedValue->KeyValue), *Value, CopySize); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList) ); CachedList[Index] = CMP_MARK_CELL_CACHED(CachedValue); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadOnly( CMP_GET_CACHED_ADDRESS(CachedList) ); // Trying to catch the BAD guy who writes over our pool. CmpMakeSpecialPoolReadOnly(CachedValue); *ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]); // // Now we have the stuff cached, use the cache data. // (*Value) = CMP_GET_CACHED_KEYVALUE(CachedValue); } else { // // If the allocation fails, just do not cache it. continue. // *ValueCached = FALSE; } } } else { // // The Valve Index Array is from the registry hive, just get the cell and move on. // (*Value) = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]); *ValueCached = FALSE; if( *Value == NULL ) { // // we couldn't map a view for this cell // just return NULL; the caller must handle it gracefully // OBS: we may remove this as we return pchild anyway; just for clarity // return SearchFail; } *CellToRelease = List->u.KeyList[Index]; } return SearchSuccess; }