410 lines
12 KiB
C
410 lines
12 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1991 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
cmtree.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains cm routines that understand the structure
|
||
|
of the registry tree.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Bryan M. Willman (bryanwi) 12-Sep-1991
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "cmp.h"
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE,CmpGetValueListFromCache)
|
||
|
#pragma alloc_text(PAGE,CmpGetValueKeyFromCache)
|
||
|
#pragma alloc_text(PAGE,CmpFindValueByNameFromCache)
|
||
|
#endif
|
||
|
|
||
|
#ifndef _CM_LDR_
|
||
|
|
||
|
PCELL_DATA
|
||
|
CmpGetValueListFromCache(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PCACHED_CHILD_LIST ChildList,
|
||
|
OUT BOOLEAN *IndexCached
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
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
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PCELL_DATA List;
|
||
|
ULONG AllocSize;
|
||
|
PCM_CACHED_VALUE_INDEX CachedValueIndex;
|
||
|
ULONG i;
|
||
|
HCELL_INDEX CellToRelease;
|
||
|
|
||
|
#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.
|
||
|
//
|
||
|
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
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a PagedPool to cache the value index cell.
|
||
|
//
|
||
|
|
||
|
AllocSize = ChildList->Count * sizeof(ULONG_PTR) + FIELD_OFFSET(CM_CACHED_VALUE_INDEX, Data);
|
||
|
// Dragos: Changed to catch the memory violator
|
||
|
// it didn't work
|
||
|
//CachedValueIndex = (PCM_CACHED_VALUE_INDEX) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_INDEX_TAG,NormalPoolPrioritySpecialPoolUnderrun);
|
||
|
CachedValueIndex = (PCM_CACHED_VALUE_INDEX) ExAllocatePoolWithTag(PagedPool, AllocSize, CM_CACHE_VALUE_INDEX_TAG);
|
||
|
|
||
|
if (CachedValueIndex) {
|
||
|
|
||
|
CachedValueIndex->CellIndex = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList);
|
||
|
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;
|
||
|
}
|
||
|
HvReleaseCell(Hive, CellToRelease);
|
||
|
}
|
||
|
#else
|
||
|
CellToRelease = CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList);
|
||
|
List = (PCELL_DATA) HvGetCell(Hive, CMP_GET_CACHED_CELL_INDEX(ChildList->ValueList));
|
||
|
*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 NULL;
|
||
|
}
|
||
|
HvReleaseCell(Hive, CellToRelease);
|
||
|
#endif
|
||
|
|
||
|
return (List);
|
||
|
}
|
||
|
|
||
|
PCM_KEY_VALUE
|
||
|
CmpGetValueKeyFromCache(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PCELL_DATA List,
|
||
|
IN ULONG Index,
|
||
|
OUT PPCM_CACHED_VALUE *ContainingList,
|
||
|
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
|
||
|
--*/
|
||
|
{
|
||
|
PCM_KEY_VALUE pchild;
|
||
|
PULONG_PTR CachedList;
|
||
|
ULONG AllocSize;
|
||
|
ULONG CopySize;
|
||
|
PCM_CACHED_VALUE CachedValue;
|
||
|
|
||
|
*CellToRelease = HCELL_NIL;
|
||
|
|
||
|
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])) {
|
||
|
pchild = CMP_GET_CACHED_KEYVALUE(CachedList[Index]);
|
||
|
*ContainingList = &((PCM_CACHED_VALUE) CachedList[Index]);
|
||
|
} else {
|
||
|
pchild = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]);
|
||
|
if( pchild == NULL ) {
|
||
|
//
|
||
|
// we couldn't map a view for this cell
|
||
|
// just return NULL; the caller must handle it gracefully
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
*CellToRelease = List->u.KeyList[Index];
|
||
|
|
||
|
//
|
||
|
// Allocate a PagedPool to cache the value node.
|
||
|
//
|
||
|
CopySize = (ULONG) HvGetCellSize(Hive, pchild);
|
||
|
AllocSize = CopySize + FIELD_OFFSET(CM_CACHED_VALUE, KeyValue);
|
||
|
|
||
|
// Dragos: Changed to catch the memory violator
|
||
|
// it didn't work
|
||
|
//CachedValue = (PCM_CACHED_VALUE) ExAllocatePoolWithTagPriority(PagedPool, AllocSize, CM_CACHE_VALUE_TAG,NormalPoolPrioritySpecialPoolUnderrun);
|
||
|
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.
|
||
|
//
|
||
|
CachedValue->DataCacheType = CM_CACHE_DATA_NOT_CACHED;
|
||
|
CachedValue->ValueKeySize = (USHORT) CopySize;
|
||
|
|
||
|
RtlCopyMemory((PVOID)&(CachedValue->KeyValue), pchild, 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.
|
||
|
//
|
||
|
pchild = 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.
|
||
|
//
|
||
|
pchild = (PCM_KEY_VALUE) HvGetCell(Hive, List->u.KeyList[Index]);
|
||
|
*ValueCached = FALSE;
|
||
|
if( pchild == 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 NULL;
|
||
|
}
|
||
|
*CellToRelease = List->u.KeyList[Index];
|
||
|
}
|
||
|
return (pchild);
|
||
|
}
|
||
|
|
||
|
PCM_KEY_VALUE
|
||
|
CmpFindValueByNameFromCache(
|
||
|
IN PHHIVE Hive,
|
||
|
IN PCACHED_CHILD_LIST ChildList,
|
||
|
IN PUNICODE_STRING Name,
|
||
|
OUT PPCM_CACHED_VALUE *ContainingList,
|
||
|
OUT ULONG *Index,
|
||
|
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!
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PCM_KEY_VALUE pchild;
|
||
|
UNICODE_STRING Candidate;
|
||
|
LONG Result;
|
||
|
PCELL_DATA List;
|
||
|
BOOLEAN IndexCached;
|
||
|
ULONG Current;
|
||
|
|
||
|
*CellToRelease = HCELL_NIL;
|
||
|
|
||
|
if (ChildList->Count != 0) {
|
||
|
List = CmpGetValueListFromCache(Hive, ChildList, &IndexCached);
|
||
|
if( List == NULL ) {
|
||
|
//
|
||
|
// couldn't map view; bail out
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// old plain hive; simulate a for
|
||
|
//
|
||
|
Current = 0;
|
||
|
|
||
|
while( TRUE ) {
|
||
|
if( *CellToRelease != HCELL_NIL ) {
|
||
|
HvReleaseCell(Hive,*CellToRelease);
|
||
|
*CellToRelease = HCELL_NIL;
|
||
|
}
|
||
|
pchild = CmpGetValueKeyFromCache(Hive, List, Current, ContainingList, IndexCached, ValueCached, CellToRelease);
|
||
|
if( pchild == NULL ) {
|
||
|
//
|
||
|
// couldn't map view; bail out
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
//
|
||
|
// Name has user-mode buffer.
|
||
|
//
|
||
|
|
||
|
if (pchild->Flags & VALUE_COMP_NAME) {
|
||
|
Result = CmpCompareCompressedName( Name,
|
||
|
pchild->Name,
|
||
|
pchild->NameLength,
|
||
|
0);
|
||
|
} else {
|
||
|
Candidate.Length = pchild->NameLength;
|
||
|
Candidate.MaximumLength = Candidate.Length;
|
||
|
Candidate.Buffer = pchild->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.
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (Result == 0) {
|
||
|
//
|
||
|
// Success, fill the index, return data to caller and exit
|
||
|
//
|
||
|
*Index = Current;
|
||
|
return(pchild);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
} // while(TRUE)
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// in the new design we shouldn't get here; we should exit the while loop with return
|
||
|
//
|
||
|
ASSERT( ChildList->Count == 0 );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#endif
|