示例#1
0
PCM_KEY_CONTROL_BLOCK
CmpCreateKeyControlBlock(
    PHHIVE          Hive,
    HCELL_INDEX     Cell,
    PCM_KEY_NODE    Node,
    PCM_KEY_CONTROL_BLOCK ParentKcb,
    BOOLEAN         FakeKey,
    PUNICODE_STRING KeyName
    )
/*++

Routine Description:

    Allocate and initialize a key control block, insert it into
    the kcb tree.

    Full path will be BaseName + '\' + KeyName, unless BaseName
    NULL, in which case the full path is simply KeyName.

    RefCount of returned KCB WILL have been incremented to reflect
    callers ref.

Arguments:

    Hive - Supplies Hive that holds the key we are creating a KCB for.

    Cell - Supplies Cell that contains the key we are creating a KCB for.

    Node - Supplies pointer to key node.

    ParentKcb - Parent kcb of the kcb to be created

    FakeKey - Whether the kcb to be create is a fake one or not

    KeyName - the subkey name to of the KCB to be created.
 
    NOTE:  We need the parameter instead of just using the name in the KEY_NODE 
           because there is no name in the root cell of a hive.

Return Value:

    NULL - failure (insufficient memory)
    else a pointer to the new kcb.

--*/
{
    PCM_KEY_CONTROL_BLOCK   kcb;
    PCM_KEY_CONTROL_BLOCK   kcbmatch=NULL;
    PCMHIVE CmHive;
    ULONG namelength;
    PUNICODE_STRING         fullname;
    ULONG       Size;
    ULONG i;

    UNICODE_STRING         NodeName;
    ULONG ConvKey=0;
    ULONG Cnt;
    WCHAR *Cp;

    //
    // ParentKCb has the base hash value.
    //
    if (ParentKcb) {
        ConvKey = ParentKcb->ConvKey;
    }

    NodeName = *KeyName;

    while ((NodeName.Length > 0) && (NodeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
        //
        // This must be the \REGISTRY.
        // Strip off the leading OBJ_NAME_PATH_SEPARATOR
        //
        NodeName.Buffer++;
        NodeName.Length -= sizeof(WCHAR);
    }

    //
    // Manually compute the hash to use.
    //
    ASSERT(NodeName.Length > 0);

    if (NodeName.Length) {
        Cp = NodeName.Buffer;
        for (Cnt=0; Cnt<NodeName.Length; Cnt += sizeof(WCHAR)) {
            if ((*Cp != OBJ_NAME_PATH_SEPARATOR) &&
                (*Cp != UNICODE_NULL)) {
                ConvKey = 37 * ConvKey + (ULONG)RtlUpcaseUnicodeChar(*Cp);
            }
            ++Cp;
        }
    }

    //
    // Create a new kcb, which we will free if one already exists
    // for this key.
    // Now it is a fixed size structure.
    //
    kcb = ExAllocatePoolWithTag(PagedPool,
                                sizeof(CM_KEY_CONTROL_BLOCK),
                                CM_KCB_TAG | PROTECTED_POOL);


    if (kcb == NULL) {
        return(NULL);
    } else {
        SET_KCB_SIGNATURE(kcb, KCB_SIGNATURE);
        INIT_KCB_KEYBODY_LIST(kcb);
        kcb->Delete = FALSE;
        kcb->RefCount = 1;
        kcb->KeyHive = Hive;
        kcb->KeyCell = Cell;
        kcb->KeyNode = Node;
        kcb->ConvKey = ConvKey;

    }

    ASSERT_KCB(kcb);
    //
    // Find location to insert kcb in kcb tree.
    //


    LOCK_KCB_TREE();

    //
    // Add the KCB to the hash table
    //
    kcbmatch = CmpInsertKeyHash(&kcb->KeyHash, FakeKey);
    if (kcbmatch != NULL) {
        //
        // A match was found.
        //
        ASSERT(!kcbmatch->Delete);
        SET_KCB_SIGNATURE(kcb, '1FmC');
        ASSERT_KEYBODY_LIST_EMPTY(kcb);
        ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
        ASSERT_KCB(kcbmatch);
        kcb = kcbmatch;
        if (kcb->RefCount == 0) {
            //
            // This kcb is on the delayed close list. Remove it from that
            // list.
            //
            CmpRemoveFromDelayedClose(kcb);
        }
        if ((USHORT)(kcb->RefCount + 1) == 0) {
            //
            // We have maxed out the ref count on this key. Probably
            // some bogus app has opened the same key 64K times without
            // ever closing it. Just fail the open, they've got enough
            // handles already.
            //
            ASSERT(kcb->RefCount + 1 != 0);
            kcb = NULL;
        } else {
            ++kcb->RefCount;
        }
    }
    else {
        //
        // No kcb created previously, fill in all the data.
        //

        //
        // Now try to reference the parentkcb
        //
        
        if (ParentKcb) {
            if (CmpReferenceKeyControlBlock(ParentKcb)) {
                kcb->ParentKcb = ParentKcb;
                kcb->TotalLevels = ParentKcb->TotalLevels + 1;
            } else {
                //
                // We have maxed out the ref count on the parent.
                // Since it has been cached in the cachetable,
                // remove it first before we free the allocation.
                //
                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '2FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        } else {
            //
            // It is the \REGISTRY node.
            //
            kcb->ParentKcb = NULL;
            kcb->TotalLevels = 1;
        }

        if (kcb) {
            //
            // Now try to find the Name Control block that has the name for this node.
            //
    
            kcb->NameBlock = CmpGetNameControlBlock (&NodeName);

            if (kcb->NameBlock) {
                //
                // Now fill in all the data needed for the cache.
                //
                kcb->ValueCache.Count = Node->ValueList.Count;
                kcb->ValueCache.ValueList = (ULONG_PTR) Node->ValueList.List;
        
                kcb->Flags = Node->Flags;
                kcb->ExtFlags = 0;
                kcb->DelayedCloseIndex = 0;
        
                //
                // Cache the security cells in the kcb
                //
                kcb->Security = Node->Security;
        
                if (FakeKey) {
                    //
                    // The KCb to be created is a fake one
                    //
                    kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
                }
            } else {
                //
                // We have maxed out the ref count on the Name.
                //
                
                //
                // First dereference the parent KCB.
                //
                CmpDereferenceKeyControlBlockWithLock(ParentKcb);

                CmpRemoveKeyControlBlock(kcb);
                SET_KCB_SIGNATURE(kcb, '3FmC');
                ASSERT_KEYBODY_LIST_EMPTY(kcb);
                ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
                kcb = NULL;
            }
        }
    }


    UNLOCK_KCB_TREE();
    return kcb;
}
示例#2
0
VOID
CmpAddToDelayedClose(
    IN PCM_KEY_CONTROL_BLOCK    kcb,
    IN BOOLEAN                  RegLockHeldEx
    )
/*++

Routine Description:

    Adds a kcb to the delayed close table

Arguments:

    kcb - the kcb in question

Note: 
    
    kcb lock/resource should be acquired exclusively when this function is called

Return Value:

    NONE.

--*/
{
    PCM_DELAYED_CLOSE_ENTRY     DelayedEntry = NULL;

    CM_PAGED_CODE();

    ASSERT( (CmpIsKCBLockedExclusive(kcb) == TRUE) || // this kcb is owned exclusive
            (CmpTestRegistryLockExclusive() == TRUE) ); // or the entire registry is locked exclusive


    // Already on delayed close, don't try to put on again
    if (kcb->DelayedCloseIndex != CmpDelayedCloseSize) { // see if we really need this
        ASSERT( FALSE );
        return;
    }

    ASSERT(kcb->RefCount == 0);

    //
    // now materialize a new entry for this kcb
    //
    ASSERT_KEYBODY_LIST_EMPTY(kcb);
    DelayedEntry = CmpDelayCloseAllocNewEntry();
    if( !DelayedEntry ) {
        //
        // this is bad luck; we need to free the kcb in place
        //
        CmpCleanUpKcbCacheWithLock(kcb,RegLockHeldEx);
        return;
    }
#if DBG
    if( kcb->InDelayClose != 0 ) {
        ASSERT( FALSE );
    }
    {
        LONG                        OldRefCount;
        LONG                        NewRefCount;

        OldRefCount = *(PLONG)&kcb->InDelayClose; //get entire dword
        ASSERT( OldRefCount == 0 );
        NewRefCount = 1;
        if( InterlockedCompareExchange((PLONG)&kcb->InDelayClose,NewRefCount,OldRefCount)
                != OldRefCount ) {
    
            ASSERT( FALSE );
        }
    }
#endif //DBG
    //
    // populate the entry and insert it into the LRU list (at the top).
    //
    kcb->DelayedCloseIndex = 0; // see if we really need this
    kcb->DelayCloseEntry = (PVOID)DelayedEntry;    // need this for removing it back from here
    DelayedEntry->KeyControlBlock = kcb;
    InterlockedIncrement((PLONG)&CmpDelayedCloseElements);

    LOCK_DELAY_CLOSE();
    InsertHeadList(
        &CmpDelayedLRUListHead,
        &(DelayedEntry->DelayedLRUList)
        );
    //
    // check if limit hit and arm timer if not already armed
    //
    if( (CmpDelayedCloseElements > CmpDelayedCloseSize) && (!CmpDelayCloseWorkItemActive) ) {
        CmpArmDelayedCloseTimer();
    } 
    UNLOCK_DELAY_CLOSE();
    //
    // we're done here
    //

}
示例#3
0
VOID
CmpCleanUpKcbCacheWithLock(
    PCM_KEY_CONTROL_BLOCK   KeyControlBlock
    )
/*++

Routine Description:

    Clean up all cached allocations that are associated to this key.
    If the parent is still open just because of this one, Remove the parent as well.

Arguments:

    KeyControlBlock - pointer to a key control block.

Return Value:

    NONE.

--*/
{
    PCM_KEY_CONTROL_BLOCK   Kcb;
    PCM_KEY_CONTROL_BLOCK   ParentKcb;

    Kcb = KeyControlBlock;

    ASSERT(KeyControlBlock->RefCount == 0);

    while (Kcb->RefCount == 0) {
        //
        // First, free allocations for Value/data.
        //
    
        CmpCleanUpKcbValueCache(Kcb);
    
        //
        // Free the kcb and dereference parentkcb and nameblock.
        //
    
        CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);
    
        if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) {
            //
            // Now free the HintIndex allocation
            //
            ExFreePoolWithTag(Kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
        }

        //
        // Save the ParentKcb before we free the Kcb
        //
        ParentKcb = Kcb->ParentKcb;
        
        //
        // We cannot call CmpDereferenceKeyControlBlockWithLock so we can avoid recurrsion.
        //
        
        if (!Kcb->Delete) {
            CmpRemoveKeyControlBlock(Kcb);
        }
        SET_KCB_SIGNATURE(Kcb, '4FmC');
        ASSERT_KEYBODY_LIST_EMPTY(Kcb);
        ExFreePoolWithTag(Kcb, CM_KCB_TAG | PROTECTED_POOL);

        Kcb = ParentKcb;
        Kcb->RefCount--;
    }
}
示例#4
0
VOID
CmpFreeKeyControlBlock( PCM_KEY_CONTROL_BLOCK kcb )

/*++

Routine Description:

    Frees a kcb; if it's allocated from our own pool put it back in the free list.
    If it's allocated from general pool, just free it.

Arguments:

    kcb to free

Return Value:


--*/
{
    USHORT			j;
	PCM_ALLOC_PAGE	AllocPage;

    PAGED_CODE();

    ASSERT_KEYBODY_LIST_EMPTY(kcb);

#if defined(_WIN64)
    //
    // free cached name if any
    //
    if( (kcb->RealKeyName != NULL) && (kcb->RealKeyName != CMP_KCB_REAL_NAME_UPCASE) ) {
        ExFreePoolWithTag(kcb->RealKeyName, CM_NAME_TAG);
    }
#endif

    if( !kcb->PrivateAlloc ) {
        //
        // just free it and be done with it
        //
        ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
        return;
    }

	LOCK_ALLOC_BUCKET();

    ASSERT_HASH_ENTRY_LOCKED_EXCLUSIVE(kcb->ConvKey);
    LogKCBFree(kcb);

    //
    // add kcb to freelist
    //
    InsertTailList(
        &CmpFreeKCBListHead,
        &(kcb->FreeListEntry)
        );

	//
	// get the page
	//
	AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );

    //
	// not all are free
	//
	ASSERT( AllocPage->FreeCount != CM_KCBS_PER_PAGE);

	AllocPage->FreeCount++;

    if( AllocPage->FreeCount == CM_KCBS_PER_PAGE ) {
        //
        // entire page is free; let it go
        //
        //
        // first; iterate through the free kcb list and remove all kcbs inside this page
        //
        for(j=0;j<CM_KCBS_PER_PAGE;j++) {
            kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
        
            RemoveEntryList(&(kcb->FreeListEntry));
        }
        ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
    }

	UNLOCK_ALLOC_BUCKET();

}