Пример #1
0
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;
    }
}
Пример #2
0
VALUE_SEARCH_RETURN_TYPE
CmpFindValueByNameFromCache(
    IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
    IN PUNICODE_STRING      Name,
    OUT PPCM_CACHED_VALUE   *ContainingList,
    OUT ULONG               *Index,
    OUT PCM_KEY_VALUE       *Value,
    OUT BOOLEAN             *ValueCached,
    OUT PHCELL_INDEX        CellToRelease
    )
/*++

Routine Description:

    Find a value node given a value list array and a value name.  It sequentially walk
    through each value node to look for a match.  If the array and 
    value nodes touched are not already cached, cache them.

Arguments:

    Hive - pointer to hive control structure for hive of interest

    ChildList - pointer/index to the Value Index array

    Name - name of value to find

    ContainlingList - The address of the entry that will receive the found cached value.

    Index - pointer to variable to receive index for child
    
    ValueCached - Indicate if the value node is cached.

Return Value:

    HCELL_INDEX for the found cell
    HCELL_NIL if not found


Notes:
    
    New hives (Minor >= 4) have ValueList sorted; this implies ValueCache is sorted too;
    So, we can do a binary search here!

--*/
{
    UNICODE_STRING      Candidate;
    LONG                Result;
    PCELL_DATA          List;
    BOOLEAN             IndexCached;
    ULONG               Current;
    HCELL_INDEX         ValueListToRelease = HCELL_NIL;
    ULONG               HashKey = 0;
    PHHIVE              Hive = KeyControlBlock->KeyHive;
    PCACHED_CHILD_LIST  ChildList = &(KeyControlBlock->ValueCache);
    VALUE_SEARCH_RETURN_TYPE    ret = SearchFail;

    ASSERT_KCB_LOCKED(KeyControlBlock);

    *CellToRelease = HCELL_NIL;
    *Value = NULL;

    if (ChildList->Count != 0) {
        ret = CmpGetValueListFromCache(KeyControlBlock,&List, &IndexCached,&ValueListToRelease);
        if( ret != SearchSuccess ) {
            //
            // retry with exclusive lock, since we need to update the cache
            // or fail altogether
            //
            ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) );    
            ASSERT( ValueListToRelease == HCELL_NIL );    
            return ret;
        } 
        
        if( IndexCached ) {
            try {
                HashKey = CmpComputeHashKey(0,Name
#if DBG
                                            , TRUE
#endif
                    );
            } except (EXCEPTION_EXECUTE_HANDLER) {
                ret = SearchFail;
                goto Exit;
            }
        }
        //
        // old plain hive; simulate a for
        //
        Current = 0;

        while( TRUE ) {
            if( *CellToRelease != HCELL_NIL ) {
                HvReleaseCell(Hive,*CellToRelease);
                *CellToRelease = HCELL_NIL;
            }
            ret =  CmpGetValueKeyFromCache(KeyControlBlock, List, Current, ContainingList, Value, IndexCached, ValueCached, CellToRelease);
            if( ret != SearchSuccess ) {
                //
                // retry with exclusive lock, since we need to update the cache
                // or fail altogether
                //
                ASSERT( (ret == SearchFail) || (CmpIsKCBLockedExclusive(KeyControlBlock) == FALSE) );    
                ASSERT( *CellToRelease == HCELL_NIL );    
                return ret;
            } 

            //
            // only compare names when hash matches.
            //
            if( IndexCached && (*ValueCached) && (HashKey != ((PCM_CACHED_VALUE)((CMP_GET_CACHED_ADDRESS(**ContainingList))))->HashKey) ) {
                //
                // no hash match; skip it
                //
#if DBG
                try {
                    //
                    // Name has user-mode buffer.
                    //

                    if ((*Value)->Flags & VALUE_COMP_NAME) {
                        Result = CmpCompareCompressedName(  Name,
                                                            (*Value)->Name,
                                                            (*Value)->NameLength,
                                                            0);
                    } else {
                        Candidate.Length = (*Value)->NameLength;
                        Candidate.MaximumLength = Candidate.Length;
                        Candidate.Buffer = (*Value)->Name;
                        Result = RtlCompareUnicodeString(   Name,
                                                            &Candidate,
                                                            TRUE);
                    }


                } except (EXCEPTION_EXECUTE_HANDLER) {
                    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode()));
                    //
                    // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it.
                    //
                    *Value = NULL;
                    ret = SearchFail;
                    goto Exit;
                }
                ASSERT( Result != 0 );
#endif
                Result = 1;
            } else {
                try {
                    //
                    // Name has user-mode buffer.
                    //

                    if( (*Value)->Flags & VALUE_COMP_NAME) {
                        Result = CmpCompareCompressedName(  Name,
                                                            (*Value)->Name,
                                                            (*Value)->NameLength,
                                                            0);
                    } else {
                        Candidate.Length = (*Value)->NameLength;
                        Candidate.MaximumLength = Candidate.Length;
                        Candidate.Buffer = (*Value)->Name;
                        Result = RtlCompareUnicodeString(   Name,
                                                            &Candidate,
                                                            TRUE);
                    }


                } except (EXCEPTION_EXECUTE_HANDLER) {
                    CmKdPrintEx((DPFLTR_CONFIG_ID,CML_EXCEPTION,"CmpFindValueByNameFromCache: code:%08lx\n", GetExceptionCode()));
                    //
                    // the caller will bail out. Some ,alicious caller altered the Name buffer since we probed it.
                    //
                    *Value = NULL;
                    ret = SearchFail;
                    goto Exit;
                }
            }
            if (Result == 0) {
                //
                // Success, fill the index, return data to caller and exit
                //
                *Index = Current;
                ret = SearchSuccess;
                goto Exit;
            }

            //
            // compute the next index to try: old'n plain hive; go on
			//
            Current++;
            if( Current == ChildList->Count ) {
                //
                // we've reached the end of the list; nicely return
                //
                (*Value) = NULL;
                ret = SearchFail;
                goto Exit;
            }

        } // while(TRUE)
Пример #3
0
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;
}