|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
cmchek.c
Abstract:
This module implements consistency checking for the registry. This module can be linked standalone, cmchek2.c cannot.
Author:
Bryan M. Willman (bryanwi) 27-Jan-92
Environment:
Revision History:
--*/
#include "cmp.h"
#define REG_MAX_PLAUSIBLE_KEY_SIZE \
((FIELD_OFFSET(CM_KEY_NODE, Name)) + \ (sizeof(WCHAR) * REG_MAX_KEY_NAME_LENGTH) + 16)
extern PCMHIVE CmpMasterHive;
//
// Private prototypes
//
ULONG CmpCheckRegistry2( PHHIVE HiveToCheck, ULONG CheckFlags, HCELL_INDEX Cell, HCELL_INDEX ParentCell, BOOLEAN ResetSD );
ULONG CmpCheckKey( PHHIVE HiveToCheck, ULONG CheckFlags, HCELL_INDEX Cell, HCELL_INDEX ParentCell, BOOLEAN ResetSD );
ULONG CmpCheckValueList( PHHIVE Hive, PCELL_DATA List, ULONG Count, HCELL_INDEX KeyCell );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmCheckRegistry)
#pragma alloc_text(PAGE,CmpCheckRegistry2)
#pragma alloc_text(PAGE,CmpCheckKey)
#pragma alloc_text(PAGE,CmpCheckValueList)
#ifdef CHECK_REGISTRY_USECOUNT
#pragma alloc_text(PAGE,CmpCheckRegistryUseCount)
#endif
#endif
//
// debug structures
//
extern struct { PHHIVE Hive; ULONG Status; } CmCheckRegistryDebug;
extern struct { PHHIVE Hive; ULONG Status; } CmpCheckRegistry2Debug;
extern struct { PHHIVE Hive; ULONG Status; HCELL_INDEX Cell; PCELL_DATA CellPoint; PVOID RootPoint; ULONG Index; } CmpCheckKeyDebug;
extern struct { PHHIVE Hive; ULONG Status; PCELL_DATA List; ULONG Index; HCELL_INDEX Cell; PCELL_DATA CellPoint; } CmpCheckValueListDebug;
ULONG CmCheckRegistry( PCMHIVE CmHive, ULONG Flags ) /*++
Routine Description:
Check consistency of the registry within a given hive. Start from root, and check that: . Each child key points back to its parent. . All allocated cells are refered to exactly once (requires looking inside the hive structure...) [This also detects space leaks.] . All allocated cells are reachable from the root.
NOTE: Exactly 1 ref rule may change with security.
Arguments:
CmHive - supplies a pointer to the CM hive control structure for the hive of interest.
Clean - if TRUE, references to volatile cells will be zapped (done at startup only to avoid groveling hives twice.) if FALSE, nothing will be changed. HiveCheck - If TRUE, performs hive consistency check too (i.e. checks the bins)
Return Value:
0 if Hive is OK. Error return indicator if not.
RANGE: 3000 - 3999
--*/ { PHHIVE Hive; ULONG rc = 0; ULONG Storage; PRELEASE_CELL_ROUTINE ReleaseCellRoutine; BOOLEAN ResetSD = FALSE;
if (CmHive == CmpMasterHive) { return(0); }
CmCheckRegistryDebug.Hive = (PHHIVE)CmHive; CmCheckRegistryDebug.Status = 0;
//
// check the underlying hive and get storage use
//
Hive = &CmHive->Hive;
if( Flags & CM_CHECK_REGISTRY_HIVE_CHECK ) { rc = HvCheckHive(Hive, &Storage); if (rc != 0) { CmCheckRegistryDebug.Status = rc; return rc; } }
//
// Store the release cell procedure so we can restore at the end;
// Set it to NULL so we don't count : this saves us some pain during the check
//
ReleaseCellRoutine = Hive->ReleaseCellRoutine; Hive->ReleaseCellRoutine = NULL;
//
// Validate all the security descriptors in the hive
//
if (!CmpValidateHiveSecurityDescriptors(Hive,&ResetSD)) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmCheckRegistry:")); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL," CmpValidateHiveSecurityDescriptors failed\n")); rc = 3040; CmCheckRegistryDebug.Status = rc; }
rc = CmpCheckRegistry2((PHHIVE)CmHive,Flags,Hive->BaseBlock->RootCell, HCELL_NIL,ResetSD);
//
// Print a bit of a summary (make sure this data avail in all error cases)
//
if (rc > 0) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmCheckRegistry Failed (%d): CmHive:%p\n", rc, CmHive)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL," Hive:%p Root:%08lx\n", Hive, Hive->BaseBlock->RootCell)); }
//
// restore the release cell routine
// this saves us some pain during the check
//
Hive->ReleaseCellRoutine = ReleaseCellRoutine;
return rc; }
#ifndef _CM_LDR_
ULONG CmpCheckRegistry2( PHHIVE HiveToCheck, ULONG CheckFlags, HCELL_INDEX Cell, HCELL_INDEX ParentCell, BOOLEAN ResetSD ) /*++
Routine Description:
Check consistency of the registry, from a particular cell on down.
. Check that the cell's value list, child key list, class, security are OK. . Check that each value entry IN the list is OK. . Apply self to each child key list.
This version uses a stack in order to parse the tree "in-depth", but not to touch any key_node.
Arguments:
Cell - HCELL_INDEX of subkey to work on.
ParentCell - expected value of parent cell for Cell, unless HCELL_NIL, in which case ignore.
Return Value:
0 if Hive is OK. Error return indicator if not.
RANGE: 4000 - 4999
--*/ { PCMP_CHECK_REGISTRY_STACK_ENTRY CheckStack; LONG StackIndex; PCM_KEY_NODE Node; ULONG rc = 0; HCELL_INDEX SubKey;
CmpCheckRegistry2Debug.Hive = HiveToCheck; CmpCheckRegistry2Debug.Status = 0; ASSERT( HiveToCheck->ReleaseCellRoutine == NULL );
//
// Initialize the stack to simulate recursion here
//
CheckStack = ExAllocatePool(PagedPool,sizeof(CMP_CHECK_REGISTRY_STACK_ENTRY)*CMP_MAX_REGISTRY_DEPTH); if (CheckStack == NULL) { CmpCheckRegistry2Debug.Status = 4099; return 4099; }
Restart:
CheckStack[0].Cell = Cell; CheckStack[0].ParentCell = ParentCell; CheckStack[0].ChildIndex = 0; CheckStack[0].CellChecked = FALSE; StackIndex = 0;
while(StackIndex >=0) { //
// first check the current cell
//
if( CheckStack[StackIndex].CellChecked == FALSE ) { CheckStack[StackIndex].CellChecked = TRUE;
rc = CmpCheckKey(HiveToCheck,CheckFlags,CheckStack[StackIndex].Cell, CheckStack[StackIndex].ParentCell,ResetSD); if (rc != 0) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tChild is list entry #%08lx\n", CheckStack[StackIndex].ChildIndex)); CmpCheckRegistry2Debug.Status = rc; if( CmDoSelfHeal() && StackIndex ) { // root cell damage is fatal.
//
// delete this key from the parent's list and restart the whole iteration (not best performance, but safest).
//
if( !CmpRemoveSubKeyCellNoCellRef(HiveToCheck,CheckStack[StackIndex].ParentCell,CheckStack[StackIndex].Cell) ) { //
// unable to delete subkey; punt.
//
break; } CmMarkSelfHeal(HiveToCheck); rc = 0; goto Restart; } else { // bail out
break; } } }
Node = (PCM_KEY_NODE)HvGetCell(HiveToCheck, CheckStack[StackIndex].Cell); if( Node == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", CheckStack[StackIndex].Cell)); CmpCheckRegistry2Debug.Status = 4098; rc = 4098; // bail out
break; }
if( CheckStack[StackIndex].ChildIndex < Node->SubKeyCounts[Stable] ) { //
// we still have childs to check; add another entry for them and advance the
// StackIndex
//
SubKey = CmpFindSubKeyByNumber(HiveToCheck, Node, CheckStack[StackIndex].ChildIndex); if( SubKey == HCELL_NIL ) { //
// we couldn't map cell;bail out
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", CheckStack[StackIndex].Cell)); CmpCheckRegistry2Debug.Status = 4097; rc = 4097; break; } //
// next iteration will check the next child
//
CheckStack[StackIndex].ChildIndex++;
StackIndex++; if( StackIndex == CMP_MAX_REGISTRY_DEPTH ) { //
// we've run out of stack; registry tree has too many levels
//
CmpCheckRegistry2Debug.Status = 4096; rc = 4096; // bail out
break; } CheckStack[StackIndex].Cell = SubKey; CheckStack[StackIndex].ParentCell = CheckStack[StackIndex-1].Cell; CheckStack[StackIndex].ChildIndex = 0; CheckStack[StackIndex].CellChecked = FALSE;
} else { //
// we have checked all childs for this node; go back
//
StackIndex--;
}
}
ExFreePool(CheckStack); return rc; }
#else
ULONG CmpCheckRegistry2( PHHIVE HiveToCheck, ULONG CheckFlags, HCELL_INDEX Cell, HCELL_INDEX ParentCell, BOOLEAN ResetSD ) /*++
Routine Description:
Check consistency of the registry, from a particular cell on down.
. Check that the cell's value list, child key list, class, security are OK. . Check that each value entry IN the list is OK. . Apply self to each child key list.
Arguments:
Cell - HCELL_INDEX of subkey to work on.
ParentCell - expected value of parent cell for Cell, unless HCELL_NIL, in which case ignore.
Return Value:
0 if Hive is OK. Error return indicator if not.
RANGE: 4000 - 4999
--*/ { ULONG Index; HCELL_INDEX StartCell; HCELL_INDEX SubKey; ULONG rc = 0; PCELL_DATA pcell; PCM_KEY_NODE Node; HCELL_INDEX EnterParent = ParentCell; HCELL_INDEX EnterCell = Cell;
CmpCheckRegistry2Debug.Hive = HiveToCheck; CmpCheckRegistry2Debug.Status = 0; ASSERT( HiveToCheck->ReleaseCellRoutine == NULL );
Restart: Cell = EnterCell; ParentCell = EnterParent; StartCell = EnterCell; Index = 0; //
// A jump to NewKey amounts to a virtual call to check the
// next child cell. (a descent into the tree)
//
// Cell, ParentCell, Index, and globals are defined
//
NewKey: rc = CmpCheckKey(HiveToCheck,CheckFlags,Cell, ParentCell,ResetSD); if (rc != 0) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tChild is list entry #%08lx\n", Index)); CmpCheckRegistry2Debug.Status = rc; if( CmDoSelfHeal() && (Cell != EnterCell)) { // root cell damage is fatal.
//
// delete this key from the parent's list and restart the whole iteration (not best performance, but safest).
//
if( !CmpRemoveSubKeyCellNoCellRef(HiveToCheck,ParentCell,Cell) ) { //
// unable to delete subkey; punt.
//
return rc; } CmMarkSelfHeal(HiveToCheck); rc = 0; goto Restart; } else { // bail out
return rc; } }
//
// save Index and check out children
//
pcell = HvGetCell(HiveToCheck, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckRegistry2Debug.Status = 4099; return 4099; } pcell->u.KeyNode.WorkVar = Index;
for (Index = 0; Index<pcell->u.KeyNode.SubKeyCounts[Stable]; Index++) {
Node = (PCM_KEY_NODE)HvGetCell(HiveToCheck,Cell); if( Node == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckRegistry2Debug.Status = 4098; return 4098; } SubKey = CmpFindSubKeyByNumber(HiveToCheck, Node, Index); if( SubKey == HCELL_NIL ) { //
// we couldn't map cell;bail out
//
return 0; }
//
// "recurse" onto child
//
ParentCell = Cell; Cell = SubKey; goto NewKey;
ResumeKey:; // A jump here is a virtual return
// Cell, ParentCell and Index
// must be defined
}
//
// since we're here, we've checked out all the children
// of the current cell.
//
if (Cell == StartCell) {
//
// we are done
//
return 0; }
//
// "return" to "parent instance"
//
pcell = HvGetCell(HiveToCheck, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckRegistry2Debug.Status = 4097; return 4097; }
Index = pcell->u.KeyNode.WorkVar;
Cell = ParentCell;
pcell = HvGetCell(HiveToCheck, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckRegistry2Debug.Status = 4096; return 4096; } ParentCell = pcell->u.KeyNode.Parent;
goto ResumeKey; }
#endif //_CM_LDR_
#if DBG
#define VOLATILE_KEY_NAME_LENGTH PAGE_SIZE
HCELL_INDEX CmpKeyCellDebug = 0; WCHAR CmpVolatileKeyNameBuffer[VOLATILE_KEY_NAME_LENGTH/2]; #endif //DBG
ULONG CmpCheckKey( PHHIVE HiveToCheck, ULONG CheckFlags, HCELL_INDEX Cell, HCELL_INDEX ParentCell, BOOLEAN ResetSD ) /*++
Routine Description:
Check consistency of the registry, for a particular cell
. Check that the cell's value list, child key list, class, security are OK. . Check that each value entry IN the list is OK.
Arguments:
Cell - HCELL_INDEX of subkey to work on.
ParentCell - expected value of parent cell for Cell, unless HCELL_NIL, in which case ignore.
Return Value:
0 if Hive is OK. Error return indicator if not.
RANGE: 4000 - 4999
--*/ { PCELL_DATA pcell; ULONG size; ULONG usedlen; ULONG ClassLength; HCELL_INDEX Class; ULONG ValueCount; HCELL_INDEX ValueList; HCELL_INDEX Security; ULONG rc = 0; ULONG nrc = 0; ULONG i; PCM_KEY_INDEX Root; PCM_KEY_INDEX Leaf; ULONG SubCount;
CmpCheckKeyDebug.Hive = HiveToCheck; CmpCheckKeyDebug.Status = 0; CmpCheckKeyDebug.Cell = Cell; CmpCheckKeyDebug.CellPoint = NULL; CmpCheckKeyDebug.RootPoint = NULL; CmpCheckKeyDebug.Index = (ULONG)-1;
#if DBG
if(CmpKeyCellDebug == Cell) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Hive = %p :: Cell to debug = %lx\n",HiveToCheck,(ULONG)Cell)); DbgBreakPoint(); } #endif //DBG
//
// Check key itself
//
if (! HvIsCellAllocated(HiveToCheck, Cell)) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tNot allocated\n")); rc = 4010; CmpCheckKeyDebug.Status = rc; return rc; } pcell = HvGetCell(HiveToCheck, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckKeyDebug.Status = 4095; return 4095; }
CmpCheckKeyDebug.CellPoint = pcell;
size = HvGetCellSize(HiveToCheck, pcell); if (size > REG_MAX_PLAUSIBLE_KEY_SIZE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tImplausible size %lx\n", size)); rc = 4020; CmpCheckKeyDebug.Status = rc; return rc; } usedlen = FIELD_OFFSET(CM_KEY_NODE, Name) + pcell->u.KeyNode.NameLength; if( (!pcell->u.KeyNode.NameLength) || (usedlen > size)) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tKey is bigger than containing cell.\n")); rc = 4030; CmpCheckKeyDebug.Status = rc; return rc; } if (pcell->u.KeyNode.Signature != CM_KEY_NODE_SIGNATURE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tNo key signature\n")); rc = 4040; CmpCheckKeyDebug.Status = rc; if( CmDoSelfHeal() ) { //
// this could be only signature corruption; fix it;
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE; rc = 0; CmMarkSelfHeal(HiveToCheck); } else { return rc; } } else { return rc; } } if (ParentCell != HCELL_NIL) { if (pcell->u.KeyNode.Parent != ParentCell) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tWrong parent value.\n")); rc = 4045; CmpCheckKeyDebug.Status = rc; if( CmDoSelfHeal() ) { //
// this could isolated corruption; fix it;
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.Parent = ParentCell; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } } ClassLength = pcell->u.KeyNode.ClassLength; Class = pcell->u.KeyNode.Class; ValueCount = pcell->u.KeyNode.ValueList.Count; ValueList = pcell->u.KeyNode.ValueList.List; Security = pcell->u.KeyNode.Security;
//
// Check simple non-empty cases
//
if (ClassLength > 0) { if( Class == HCELL_NIL ) { pcell->u.KeyNode.ClassLength = 0; HvMarkCellDirty(HiveToCheck, Cell); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx has ClassLength = %lu and Class == HCELL_NIL\n", HiveToCheck, Cell,ClassLength)); } else { if (HvIsCellAllocated(HiveToCheck, Class) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tClass:%08lx - unallocated class\n", Class)); rc = 4080; CmpCheckKeyDebug.Status = rc; if( CmDoSelfHeal() ) { //
// yank the class
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.Class = HCELL_NIL; pcell->u.KeyNode.ClassLength = 0; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } } }
if (Security != HCELL_NIL) { if ((HvIsCellAllocated(HiveToCheck, Security) == FALSE) || ((ParentCell != HCELL_NIL) && CmDoSelfHeal() && ResetSD) ) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tSecurity:%08lx - unallocated security\n", Security)); rc = 4090; CmpCheckKeyDebug.Status = rc; goto SetParentSecurity; } //
// Else CmpValidateHiveSecurityDescriptors must do computation
//
} else { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"SecurityCell is HCELL_NIL for (%p,%08lx) !!!\n", HiveToCheck, Cell)); rc = 4130; CmpCheckKeyDebug.Status = rc; SetParentSecurity: if( CmDoSelfHeal() ) { //
// attempt to set the same security as it's parent
//
PCM_KEY_NODE ParentNode = NULL; PCM_KEY_SECURITY SecurityNode = NULL;
if( ParentCell != HCELL_NIL ) { ParentNode = (PCM_KEY_NODE )HvGetCell(HiveToCheck, ParentCell); SecurityNode = (PCM_KEY_SECURITY)HvGetCell(HiveToCheck, ParentNode->Security); }
if( ParentNode == NULL || SecurityNode == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
return rc; }
if( HvMarkCellDirty(HiveToCheck, Cell) && HvMarkCellDirty(HiveToCheck, ParentNode->Security) ) { pcell->u.KeyNode.Security = ParentNode->Security; SecurityNode->ReferenceCount++; rc = 0; CmMarkSelfHeal(HiveToCheck); } else { return rc; } } else { return rc; } }
//
// Check value list case
//
if (ValueCount > 0) { if (HvIsCellAllocated(HiveToCheck, ValueList) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tValueList:%08lx - unallocated valuelist\n", ValueList)); rc = 4100; CmpCheckKeyDebug.Status = rc; goto YankValueList; } else { pcell = HvGetCell(HiveToCheck, ValueList); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", ValueList)); CmpCheckKeyDebug.Status = 4094; return 4094; } if( ValueCount * sizeof(HCELL_INDEX) > (ULONG)HvGetCellSize(HiveToCheck,pcell) ) { //
// implausible value count.
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tValueList:%08lx - Implausible ValueCount = %08lx\n", ValueList,ValueCount)); rc = 4095; CmpCheckKeyDebug.Status = rc; goto YankValueList; }
nrc = CmpCheckValueList(HiveToCheck, pcell, ValueCount,Cell); if (nrc != 0) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"List was for HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); rc = nrc; CmpCheckKeyDebug.CellPoint = pcell; CmpCheckKeyDebug.Status = rc; YankValueList: if( CmDoSelfHeal() ) { PCM_KEY_NODE KeyNode; //
// make the key valueless
//
if( HvMarkCellDirty(HiveToCheck, Cell) && (KeyNode = (PCM_KEY_NODE)HvGetCell(HiveToCheck, Cell) ) ) { KeyNode->ValueList.Count = 0; KeyNode->ValueList.List = HCELL_NIL; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } } }
//
// Check subkey list case
//
pcell = HvGetCell(HiveToCheck, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckKeyDebug.Status = 4093; return 4093; } CmpCheckKeyDebug.CellPoint = pcell; if ((HvGetCellType(Cell) == Volatile) && (pcell->u.KeyNode.SubKeyCounts[Stable] != 0)) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tVolatile Cell has Stable children\n")); rc = 4108; CmpCheckKeyDebug.Status = rc; return rc; } else if (pcell->u.KeyNode.SubKeyCounts[Stable] > 0) { if (! HvIsCellAllocated(HiveToCheck, pcell->u.KeyNode.SubKeyLists[Stable])) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tStableKeyList:%08lx - unallocated\n", pcell->u.KeyNode.SubKeyLists[Stable])); rc = 4110; CmpCheckKeyDebug.Status = rc; goto YankStableSubkeys; } else { //
// Prove that the index is OK
//
Root = (PCM_KEY_INDEX)HvGetCell( HiveToCheck, pcell->u.KeyNode.SubKeyLists[Stable] ); if( Root == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", pcell->u.KeyNode.SubKeyLists[Stable])); CmpCheckKeyDebug.Status = 4093; return 4093; } CmpCheckKeyDebug.RootPoint = Root; if ((Root->Signature == CM_KEY_INDEX_LEAF) || (Root->Signature == CM_KEY_FAST_LEAF) || (Root->Signature == CM_KEY_HASH_LEAF) ) { if ((ULONG)Root->Count != pcell->u.KeyNode.SubKeyCounts[Stable]) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBad Index count @%08lx\n", Root)); rc = 4120; CmpCheckKeyDebug.Status = rc; if( CmDoSelfHeal() ) { //
// fix the subkeycount
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.SubKeyCounts[Stable] = (ULONG)Root->Count; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } } else if (Root->Signature == CM_KEY_INDEX_ROOT) { SubCount = 0; for (i = 0; i < Root->Count; i++) { CmpCheckKeyDebug.Index = i; if (! HvIsCellAllocated(HiveToCheck, Root->List[i])) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: Hive:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBad Leaf Cell %08lx Root@%08lx\n", Root->List[i], Root)); rc = 4130; CmpCheckKeyDebug.Status = rc; goto YankStableSubkeys; } Leaf = (PCM_KEY_INDEX)HvGetCell(HiveToCheck, Root->List[i]); if( Leaf == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Root->List[i])); CmpCheckKeyDebug.Status = 4092; return 4092; }
if ((Leaf->Signature != CM_KEY_INDEX_LEAF) && (Leaf->Signature != CM_KEY_FAST_LEAF) && (Leaf->Signature != CM_KEY_HASH_LEAF) ) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBad Leaf Index @%08lx Root@%08lx\n", Leaf, Root)); rc = 4140; CmpCheckKeyDebug.Status = rc; goto YankStableSubkeys; } SubCount += Leaf->Count; } if (pcell->u.KeyNode.SubKeyCounts[Stable] != SubCount) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBad count in index, SubCount=%08lx\n", SubCount)); rc = 4150; CmpCheckKeyDebug.Status = rc; if( CmDoSelfHeal() ) { //
// fix the subkeycount
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.SubKeyCounts[Stable] = SubCount; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } } else { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckKey: HiveToCheck:%p Cell:%08lx\n", HiveToCheck, Cell)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tBad Root index signature @%08lx\n", Root)); rc = 4120; CmpCheckKeyDebug.Status = rc; goto YankStableSubkeys; } } } if( FALSE ) { YankStableSubkeys: if( CmDoSelfHeal() ) { //
// mark the key as no subkeys
//
if( HvMarkCellDirty(HiveToCheck, Cell) ) { pcell->u.KeyNode.SubKeyCounts[Stable] = 0; pcell->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL; CmMarkSelfHeal(HiveToCheck); rc = 0; } else { return rc; } } else { return rc; } } //
// force volatiles to be empty, if this is a load operation
//
if ( (CheckFlags & CM_CHECK_REGISTRY_FORCE_CLEAN) || // force clear out volatile info
( ( CheckFlags & (CM_CHECK_REGISTRY_CHECK_CLEAN | CM_CHECK_REGISTRY_LOADER_CLEAN) ) && // if asked to clear volatile info
( pcell->u.KeyNode.SubKeyCounts[Volatile] != 0 ) // there is some volatile info saved from a previous version
) || ( ( CheckFlags & CM_CHECK_REGISTRY_SYSTEM_CLEAN ) && // system hive special case; the loader has cleaned only subkeycount
(( pcell->u.KeyNode.SubKeyLists[Volatile] != HCELL_NIL ) || // now it is our job to clear Subkeylist, too
(HiveToCheck->Version < HSYS_WHISTLER_BETA1) ) ) ) { //
// go ahead and clear the volatile info for this key
//
if( CheckFlags & CM_CHECK_REGISTRY_SYSTEM_CLEAN ) { //
// the loader must've left this on the previous value and cleared only the count
//
ASSERT( pcell->u.KeyNode.SubKeyLists[Volatile] == 0xBAADF00D || HiveToCheck->Version < HSYS_WHISTLER_BETA1 ); ASSERT( pcell->u.KeyNode.SubKeyCounts[Volatile] == 0 ); #if DBG
#ifndef _CM_LDR_
//
// see who those volatile keys are
//
{ ULONG TotalLength = 0; HCELL_INDEX CurrCell = Cell; PCM_KEY_NODE CurrNode; PUCHAR Dest; ULONG k;
Dest = ((PUCHAR)CmpVolatileKeyNameBuffer) + VOLATILE_KEY_NAME_LENGTH - 2; while(TRUE) { CurrNode = (PCM_KEY_NODE)HvGetCell(HiveToCheck,CurrCell); Dest -= CurrNode->NameLength; TotalLength += CurrNode->NameLength; if (CurrNode->Flags & KEY_COMP_NAME) { Dest -= CurrNode->NameLength; for (k=0;k<CurrNode->NameLength;k++) { ((PWCHAR)Dest)[k] = (WCHAR)(((PUCHAR)CurrNode->Name)[k]); } } else { RtlCopyMemory( Dest, CurrNode->Name, CurrNode->NameLength ); } Dest -= 2; TotalLength += (CurrNode->NameLength +2); ((PWCHAR)Dest)[0] = (WCHAR)'\\'; if( CurrCell == HiveToCheck->BaseBlock->RootCell ) { break; } CurrCell = CurrNode->Parent; } CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"%.*S\n",TotalLength/2,Dest)); } #endif
#endif
}
HvMarkCellDirty(HiveToCheck, Cell); //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Clear Volatile Info for Hive = %p Cell = %lx\n", HiveToCheck, Cell));
pcell->u.KeyNode.SubKeyCounts[Volatile] = 0; if( (CheckFlags & CM_CHECK_REGISTRY_LOADER_CLEAN) && (HiveToCheck->Version >= HSYS_WHISTLER_BETA1) ) { //
// mark this as bad food
//
pcell->u.KeyNode.SubKeyLists[Volatile] = 0xBAADF00D; } else { //
// clean it up
//
pcell->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL; } }
return rc; }
ULONG CmpCheckValueList( PHHIVE Hive, PCELL_DATA List, ULONG Count, HCELL_INDEX KeyCell ) /*++
Routine Description:
Check consistency of a value list. . Each element allocated? . Each element have valid signature? . Data properly allocated?
Arguments:
Hive - containing Hive.
List - pointer to an array of HCELL_INDEX entries.
Count - number of entries in list.
Return Value:
0 if Hive is OK. Error return indicator if not.
RANGE: 5000 - 5999
--*/ { ULONG i = 0,j; HCELL_INDEX Cell; PCELL_DATA pcell; ULONG size; ULONG usedlen; ULONG DataLength; HCELL_INDEX Data; ULONG rc = 0;
CmpCheckValueListDebug.Hive = Hive; CmpCheckValueListDebug.Status = 0; CmpCheckValueListDebug.List = List; CmpCheckValueListDebug.Index = (ULONG)-1; CmpCheckValueListDebug.Cell = 0; // NOT HCELL_NIL
CmpCheckValueListDebug.CellPoint = NULL;
if( FALSE ) { RemoveThisValue: if( CmDoSelfHeal() ) { //
// remove value at index i
//
PCM_KEY_NODE Node; Node = (PCM_KEY_NODE)HvGetCell(Hive,KeyCell); if( Node == NULL ) { return rc; } HvReleaseCell(Hive,KeyCell);
if( HvMarkCellDirty(Hive, KeyCell) && HvMarkCellDirty(Hive, Node->ValueList.List)) { Node->ValueList.Count--; Count--; RtlMoveMemory(&(List->u.KeyList[i]),&(List->u.KeyList[i+1]),(Count - i)*sizeof(HCELL_INDEX)); rc = 0; CmMarkSelfHeal(Hive); } else { return rc; } } else { return rc; } }
for (; i < Count; i++) {
//
// Check out value entry's refs.
//
Cell = List->u.KeyList[i]; if (Cell == HCELL_NIL) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tEntry is null\n")); rc = 5010; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; goto RemoveThisValue; } if (HvIsCellAllocated(Hive, Cell) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tEntry is not allocated\n")); rc = 5020; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; goto RemoveThisValue; }
//
// Check out the value entry itself
//
pcell = HvGetCell(Hive, Cell); if( pcell == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Cell)); CmpCheckValueListDebug.Status = 5099; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; rc = 5099; goto Exit; } size = HvGetCellSize(Hive, pcell); if (pcell->u.KeyValue.Signature != CM_KEY_VALUE_SIGNATURE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx - invalid value signature\n", Cell)); rc = 5030; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; goto RemoveThisValue; } usedlen = FIELD_OFFSET(CM_KEY_VALUE, Name) + pcell->u.KeyValue.NameLength; if (usedlen > size) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx - value bigger than containing cell\n", Cell)); rc = 5040; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; goto RemoveThisValue; }
//
// Check out value entry's data
//
DataLength = pcell->u.KeyValue.DataLength; if (DataLength < CM_KEY_VALUE_SPECIAL_SIZE) { Data = pcell->u.KeyValue.Data; if ((DataLength == 0) && (Data != HCELL_NIL)) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx Data:%08lx - data not null\n", Cell, Data)); rc = 5050; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; goto RemoveThisValue; } if (DataLength > 0) { if (HvIsCellAllocated(Hive, Data) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx Data:%08lx - unallocated\n", Cell, Data)); rc = 5060; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Cell; CmpCheckValueListDebug.CellPoint = pcell; goto RemoveThisValue; } } if( CmpIsHKeyValueBig(Hive,DataLength) == TRUE ) { PCM_BIG_DATA BigData; PHCELL_INDEX Plist;
BigData = (PCM_BIG_DATA)HvGetCell(Hive, Data); if( BigData == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", Data)); CmpCheckValueListDebug.Status = 5098; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Data; rc = 5098; goto Exit; } if( (BigData->Signature != CM_BIG_DATA_SIGNATURE) || (BigData->Count == 0 ) || (BigData->List == HCELL_NIL) ) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tinvalid big data cell #%08lx\n", Data)); CmpCheckValueListDebug.Status = 5097; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = Data; rc = 5097; goto RemoveThisValue; } if (HvIsCellAllocated(Hive, BigData->List) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p i:%08lx\n", List, i)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx DataList:%08lx - unallocated\n", Cell, BigData->List)); rc = 5096; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = BigData->List; CmpCheckValueListDebug.CellPoint = (PCELL_DATA)BigData; goto RemoveThisValue; }
Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List); if( Plist == NULL ) { //
// we couldn't map a view for the bin containing this cell
//
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCould not map cell #%08lx\n", BigData->List)); CmpCheckValueListDebug.Status = 5098; CmpCheckValueListDebug.Index = i; CmpCheckValueListDebug.Cell = BigData->List; rc = 5095; goto Exit; }
//
// check each and every big data cell to see if it is allocated.
//
for(j=0;j<BigData->Count;j++) { if (HvIsCellAllocated(Hive, Plist[j]) == FALSE) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpCheckValueList: List:%p j:%08lx\n", BigData->List, j)); CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\tCell:%08lx BigData:%08lx - unallocated\n", Plist[j], BigData->List)); rc = 5094; CmpCheckValueListDebug.Status = rc; CmpCheckValueListDebug.Index = j; CmpCheckValueListDebug.Cell = Plist[j]; CmpCheckValueListDebug.CellPoint = (PCELL_DATA)BigData; goto RemoveThisValue; } } }
} }
Exit: // cleanup
return rc; }
#ifdef CHECK_REGISTRY_USECOUNT
extern LIST_ENTRY CmpHiveListHead;
VOID CmpCheckRegistryUseCount( ) { PLIST_ENTRY p; PCMHIVE CmHive;
ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); LOCK_HIVE_LIST(); p = CmpHiveListHead.Flink; while(p != &CmpHiveListHead) { CmHive = CONTAINING_RECORD(p, CMHIVE, HiveList); if( CmHive->UseCount != 0 ){ DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Hive (%p) is supposed to have USECount == 0 at this point; instead UseCount = %lu\n",CmHive,CmHive->UseCount); DbgBreakPoint(); }
p=p->Flink; } UNLOCK_HIVE_LIST();
} #endif
|