ReactOS 0.4.16-dev-306-g647d351
cmcheck.c File Reference
#include "cmlib.h"
#include <debug.h>
Include dependency graph for cmcheck.c:

Go to the source code of this file.

Classes

struct  _CMP_REGISTRY_STACK_WORK_STATE
 

Macros

#define NDEBUG
 
#define GET_HHIVE(CmHive)   (&((CmHive)->Hive))
 
#define GET_HHIVE_ROOT_CELL(Hive)   ((Hive)->BaseBlock->RootCell)
 
#define GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex)   ((PHBIN)Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress)
 
#define GET_CELL_BIN(Bin)   ((PHCELL)((PUCHAR)Bin + sizeof(HBIN)))
 
#define IS_CELL_VOLATILE(Cell)   (HvGetCellType(Cell) == Volatile)
 
#define CMP_PRIOR_STACK   1
 
#define CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH   512
 
#define CMP_KEY_SIZE_THRESHOLD   0x45C
 
#define CMP_VOLATILE_LIST_UNINTIALIZED   0xBAADF00D
 

Typedefs

typedef struct _CMP_REGISTRY_STACK_WORK_STATE CMP_REGISTRY_STACK_WORK_STATE
 
typedef struct _CMP_REGISTRY_STACK_WORK_STATEPCMP_REGISTRY_STACK_WORK_STATE
 

Functions

static BOOLEAN CmpValidateLexicalOrder (_In_ PHHIVE Hive, _In_ HCELL_INDEX Child, _In_ HCELL_INDEX Sibling)
 Validates the lexicographical order between a child and prior sibling of the said child.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateClass (_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData)
 Validates the class of a given key cell.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateValueListByCount (_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ ULONG ListCount, _In_ PCELL_DATA ValueListData, _Out_ PULONG ValuesRemoved, _In_ BOOLEAN FixHive)
 Validates each value in the list by count. A value that is damaged gets removed from the list. This routine performs self-healing process in this case.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateValueList (_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
 Validates the value list of a key. If the list is damaged due to corruption, the whole list is expunged. This function performs self-healing procedures in this case.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateSubKeyList (_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive, _Out_ PBOOLEAN DoRepair)
 Validates the subkeys list of a key. If the list is damaged from corruption, the function can either salvage this list or purge the whole of it. The function performs different validation steps for different storage types.
 
static VOID CmpPurgeVolatiles (_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ ULONG Flags)
 Purges the volatile storage of a registry hive. This operation is done mainly during the bootup of the system.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateKey (_In_ PHHIVE Hive, _In_ BOOLEAN SecurityDefaulted, _In_ HCELL_INDEX ParentCell, _In_ HCELL_INDEX CurrentCell, _In_ ULONG Flags, _In_ BOOLEAN FixHive)
 Validates the key cell, ensuring that the key in the registry is valid and not corrupted.
 
static CM_CHECK_REGISTRY_STATUS CmpValidateRegistryInternal (_In_ PHHIVE Hive, _In_ ULONG Flags, _In_ BOOLEAN SecurityDefaulted, _In_ BOOLEAN FixHive)
 Performs deep checking of the registry by walking down the registry tree using a stack based pool. This function is the guts of CmCheckRegistry.
 
CM_CHECK_REGISTRY_STATUS NTAPI HvValidateBin (_In_ PHHIVE Hive, _In_ PHBIN Bin)
 Validates a bin from a hive. It performs checks against the cells from this bin, ensuring the bin is not corrupt and that the cells are consistent with each other.
 
CM_CHECK_REGISTRY_STATUS NTAPI HvValidateHive (_In_ PHHIVE Hive)
 Validates a registry hive. This function ensures that the storage of this hive has valid bins.
 
CM_CHECK_REGISTRY_STATUS NTAPI CmCheckRegistry (_In_ PCMHIVE RegistryHive, _In_ ULONG Flags)
 Checks the registry that is consistent and its contents valid and not corrupted. More specifically this function performs a deep check of the registry for the following properties:
 

Variables

PCMHIVE CmiVolatileHive
 

Macro Definition Documentation

◆ CMP_KEY_SIZE_THRESHOLD

#define CMP_KEY_SIZE_THRESHOLD   0x45C

Definition at line 38 of file cmcheck.c.

◆ CMP_PRIOR_STACK

#define CMP_PRIOR_STACK   1

Definition at line 35 of file cmcheck.c.

◆ CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH

#define CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH   512

Definition at line 36 of file cmcheck.c.

◆ CMP_VOLATILE_LIST_UNINTIALIZED

#define CMP_VOLATILE_LIST_UNINTIALIZED   0xBAADF00D

Definition at line 39 of file cmcheck.c.

◆ GET_CELL_BIN

#define GET_CELL_BIN (   Bin)    ((PHCELL)((PUCHAR)Bin + sizeof(HBIN)))

Definition at line 27 of file cmcheck.c.

◆ GET_HHIVE

#define GET_HHIVE (   CmHive)    (&((CmHive)->Hive))

Definition at line 24 of file cmcheck.c.

◆ GET_HHIVE_BIN

#define GET_HHIVE_BIN (   Hive,
  StorageIndex,
  BlockIndex 
)    ((PHBIN)Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress)

Definition at line 26 of file cmcheck.c.

◆ GET_HHIVE_ROOT_CELL

#define GET_HHIVE_ROOT_CELL (   Hive)    ((Hive)->BaseBlock->RootCell)

Definition at line 25 of file cmcheck.c.

◆ IS_CELL_VOLATILE

#define IS_CELL_VOLATILE (   Cell)    (HvGetCellType(Cell) == Volatile)

Definition at line 29 of file cmcheck.c.

◆ NDEBUG

#define NDEBUG

Definition at line 9 of file cmcheck.c.

Typedef Documentation

◆ CMP_REGISTRY_STACK_WORK_STATE

◆ PCMP_REGISTRY_STACK_WORK_STATE

Function Documentation

◆ CmCheckRegistry()

CM_CHECK_REGISTRY_STATUS NTAPI CmCheckRegistry ( _In_ PCMHIVE  RegistryHive,
_In_ ULONG  Flags 
)

Checks the registry that is consistent and its contents valid and not corrupted. More specifically this function performs a deep check of the registry for the following properties:

  • That the security cache cell of the registry is OK
  • That bins and cells are consistent with each other
  • That the child subkey cell points to the parent
  • That the key itself has sane sizes
  • That the class, values and subkeys lists are valid
  • Much more
Parameters
[in]HiveA pointer to a CM hive of the registry to be checked in question.
[in]FlagsA bit mask flag used to influence the process of volatile keys purging. See Remarks for further information.
Returns
This function returns a CM (Configuration Manager) check registry status code. A code of CM_CHECK_REGISTRY_GOOD of value 0 indicates the registry hive is valid and not corrupted. A non zero unsigned integer value indicates a failure. Consult other private routines in this file for other failure status codes.
Remarks
During a load operation CmCheckRegistry can purge the volatile data of registry (or not) depending on the submitted flag bit mask by the caller. The following supported flags are:

CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES – Tells the function that volatile data purging must not be done.

CM_CHECK_REGISTRY_PURGE_VOLATILES - Tells the function to purge out volatile information data from a registry hive, on demand. Purging doesn't come into action if no volatile data has been found.

CM_CHECK_REGISTRY_BOOTLOADER_PURGE_VOLATILES - A special flag used by FreeLdr and Environ. When this flag is set the function will not clean up the volatile storage but it will unintialize the storage instead (this is the case if the given registry hive for validation is a XP Beta 1 hive or newer). Otherwise it will perform a normal cleanup of the volatile storage.

CM_CHECK_REGISTRY_VALIDATE_HIVE - Tells the function to perform a thorough analysation of the underlying hive's bins and cells before doing validation of the registry tree. HvValidateHive function is called in this case.

CM_CHECK_REGISTRY_FIX_HIVE - Tells the function to fix the target registry hive if it is damaged. Usually this flag comes from a registry repair tool where the user asked to for its damaged hive to be fixed. In this case a self-heal procedure against the hive is performed.

Definition at line 1634 of file cmcheck.c.

1637{
1638 CM_CHECK_REGISTRY_STATUS CmStatusCode;
1639 PHHIVE Hive;
1640 BOOLEAN ShouldFixHive = FALSE;
1641
1642 PAGED_CODE();
1643
1644 /* Bail out if the caller did not give a hive */
1645 if (!RegistryHive)
1646 {
1647 DPRINT1("No registry hive given for check\n");
1649 }
1650
1651#if !defined(CMLIB_HOST) && !defined(_BLDR_)
1652 /*
1653 * The master hive is the root of the registry,
1654 * it holds all other hives together. So do not
1655 * do any validation checks.
1656 */
1657 if (RegistryHive == CmiVolatileHive)
1658 {
1659 DPRINT("This is master registry hive, don't do anything\n");
1661 }
1662#endif
1663
1664 /* Bail out if no valid flag is given */
1670 {
1671 DPRINT1("Invalid flag for registry check given (flag %u)\n", Flags);
1673 }
1674
1675 /*
1676 * Obtain the hive and check if the caller wants
1677 * that the hive to be validated.
1678 */
1679 Hive = GET_HHIVE(RegistryHive);
1681 {
1682 CmStatusCode = HvValidateHive(Hive);
1683 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1684 {
1685 DPRINT1("The hive is not valid (hive 0x%p, check status code %u)\n",
1686 Hive, CmStatusCode);
1687 return CmStatusCode;
1688 }
1689 }
1690
1691 /*
1692 * A registry repair tool such as the ReactOS Check Registry
1693 * Utility wants the damaged hive to be fixed as we check the
1694 * target hive.
1695 */
1697 {
1698 ShouldFixHive = TRUE;
1699 }
1700
1701 /*
1702 * FIXME: Currently ReactOS does not implement security
1703 * caching algorithms so it's pretty pointless to implement
1704 * security descriptors validation checks at this moment.
1705 * When the time comes to implement these, we would need
1706 * to implement security checks here as well.
1707 */
1708
1709 /* Call the internal API to do the rest of the work bulk */
1710 CmStatusCode = CmpValidateRegistryInternal(Hive, Flags, FALSE, ShouldFixHive);
1711 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1712 {
1713 DPRINT1("The hive is not valid (hive 0x%p, check status code %u)\n",
1714 Hive, CmStatusCode);
1715 return CmStatusCode;
1716 }
1717
1718 return CmStatusCode;
1719}
#define PAGED_CODE()
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
CM_CHECK_REGISTRY_STATUS NTAPI HvValidateHive(_In_ PHHIVE Hive)
Validates a registry hive. This function ensures that the storage of this hive has valid bins.
Definition: cmcheck.c:1506
#define GET_HHIVE(CmHive)
Definition: cmcheck.c:24
static CM_CHECK_REGISTRY_STATUS CmpValidateRegistryInternal(_In_ PHHIVE Hive, _In_ ULONG Flags, _In_ BOOLEAN SecurityDefaulted, _In_ BOOLEAN FixHive)
Performs deep checking of the registry by walking down the registry tree using a stack based pool....
Definition: cmcheck.c:1148
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
#define CM_CHECK_REGISTRY_INVALID_PARAMETER
Definition: cmlib.h:238
#define CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES
Definition: cmlib.h:228
#define CM_CHECK_REGISTRY_GOOD
Definition: cmlib.h:237
#define CM_CHECK_REGISTRY_PURGE_VOLATILES
Definition: cmlib.h:229
#define CM_CHECK_REGISTRY_VALIDATE_HIVE
Definition: cmlib.h:231
#define CM_CHECK_REGISTRY_FIX_HIVE
Definition: cmlib.h:232
#define CM_CHECK_REGISTRY_SUCCESS(StatusCode)
Definition: cmlib.h:281
ULONG CM_CHECK_REGISTRY_STATUS
Definition: cmlib.h:223
#define CM_CHECK_REGISTRY_BOOTLOADER_PURGE_VOLATILES
Definition: cmlib.h:230
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define DPRINT
Definition: sndvol32.h:73
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

Referenced by BiInitializeAndValidateHive(), CmFlushKey(), CmpInitializeHive(), CmSaveKey(), CmSaveMergedKeys(), and RegInitializeHive().

◆ CmpPurgeVolatiles()

static VOID CmpPurgeVolatiles ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  CurrentCell,
_Inout_ PCELL_DATA  CellData,
_In_ ULONG  Flags 
)
static

Purges the volatile storage of a registry hive. This operation is done mainly during the bootup of the system.

Parameters
[in]HiveA pointer to a hive descriptor of which volatiles are to be purged.
[in]CurrentCellThe current key cell that the volatile storage of the hive points to.
[in]CellDataThe cell data of the current cell of which the volatile subkeys storage comes from.
[in]FlagsA bit mask flag that is used to influence how is the purging operation to be done. See CmCheckRegistry documentation below for more information.

Definition at line 849 of file cmcheck.c.

854{
855 PAGED_CODE();
856
857 ASSERT(CellData);
858
859 /* Did the caller ask to purge volatiles? */
862 (CellData->u.KeyNode.SubKeyCounts[Volatile] != 0))
863 {
864 /*
865 * OK, the caller wants them cleaned from this
866 * hive. For XP Beta 1 or newer hives, we unintialize
867 * the whole volatile subkeys list. For older hives,
868 * we just do a cleanup.
869 */
870#if !defined(_BLDR_)
871 HvMarkCellDirty(Hive, CurrentCell, FALSE);
872#endif
874 (Hive->Version >= HSYS_WHISTLER_BETA1))
875 {
876 CellData->u.KeyNode.SubKeyLists[Volatile] = CMP_VOLATILE_LIST_UNINTIALIZED;
877 }
878 else
879 {
880 CellData->u.KeyNode.SubKeyLists[Volatile] = HCELL_NIL;
881 }
882
883 /* Clear the count */
884 CellData->u.KeyNode.SubKeyCounts[Volatile] = 0;
885 }
886}
#define CMP_VOLATILE_LIST_UNINTIALIZED
Definition: cmcheck.c:39
BOOLEAN CMAPI HvMarkCellDirty(PHHIVE RegistryHive, HCELL_INDEX CellOffset, BOOLEAN HoldingLock)
Definition: hivecell.c:109
@ Volatile
Definition: hivedata.h:128
#define HCELL_NIL
Definition: hivedata.h:110
#define HSYS_WHISTLER_BETA1
Definition: hivedata.h:71
#define ASSERT(a)
Definition: mode.c:44

Referenced by CmpValidateKey().

◆ CmpValidateClass()

static CM_CHECK_REGISTRY_STATUS CmpValidateClass ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  CurrentCell,
_Inout_ PCELL_DATA  CellData 
)
static

Validates the class of a given key cell.

Parameters
[in]HiveA pointer to a hive descriptor of which the registry call is to be validated.
[in]CurrentCellThe current key cell that the class points to.
[in]CellDataA pointer to cell data of the current key cell that contains the class to be validated.
Returns
Returns CM_CHECK_REGISTRY_GOOD if the class is in good shape. The same CM status code is returned if the class doesn't but the class length says otherwise. CM_CHECK_REGISTRY_KEY_CLASS_UNALLOCATED is returned if the class cell is not allocated.

Definition at line 190 of file cmcheck.c.

194{
195 ULONG ClassLength;
196 HCELL_INDEX ClassCell;
197
198 PAGED_CODE();
199
200 ASSERT(CurrentCell != HCELL_NIL);
201 ASSERT(CellData);
202
203 /* Cache the class cell and validate it (if any) */
204 ClassCell = CellData->u.KeyNode.Class;
205 ClassLength = CellData->u.KeyNode.ClassLength;
206 if (ClassLength > 0)
207 {
208 if (ClassCell == HCELL_NIL)
209 {
210 /*
211 * Somebody has freed the class but left the
212 * length as is, reset it.
213 */
214 DPRINT1("The key node class is NIL but the class length is not 0, resetting it\n");
215 HvMarkCellDirty(Hive, CurrentCell, FALSE);
216 CellData->u.KeyNode.ClassLength = 0;
218 }
219
220 if (!HvIsCellAllocated(Hive, ClassCell))
221 {
222 DPRINT1("The key class is not allocated\n");
224 }
225 }
226
228}
BOOLEAN CMAPI HvIsCellAllocated(IN PHHIVE RegistryHive, IN HCELL_INDEX CellIndex)
Definition: hivecell.c:53
#define CM_CHECK_REGISTRY_KEY_CLASS_UNALLOCATED
Definition: cmlib.h:258
ULONG HCELL_INDEX
Definition: hivedata.h:105
uint32_t ULONG
Definition: typedefs.h:59

Referenced by CmpValidateKey().

◆ CmpValidateKey()

static CM_CHECK_REGISTRY_STATUS CmpValidateKey ( _In_ PHHIVE  Hive,
_In_ BOOLEAN  SecurityDefaulted,
_In_ HCELL_INDEX  ParentCell,
_In_ HCELL_INDEX  CurrentCell,
_In_ ULONG  Flags,
_In_ BOOLEAN  FixHive 
)
static

Validates the key cell, ensuring that the key in the registry is valid and not corrupted.

Parameters
[in]HiveA pointer to a hive descriptor of the registry where the key is to be validated.
[in]SecurityDefaultedIf the caller sets this to TRUE, this indicates the hive has its security property defaulted due to heal recovery of the said security. If the caller sets this to FALSE, the hive comes with its own security details. This parameter is currently unused.
[in]ParentCellThe parent key cell that comes before the current cell. This parameter can be HCELL_NIL if the first cell is the root cell which is the parent of its own.
[in]CurrentCellThe current child key cell that is to be validated.
[in]FlagsA bit mask flag that is used to influence how is the purging operation of volatile keys in the volatile storage to be done. See CmCheckRegistry documentation below for more information.
[in]FixHiveIf set to TRUE, the target hive will be fixed.
Returns
Returns CM_CHECK_REGISTRY_GOOD if the key that has been validated is valid and not corrupted. CM_CHECK_REGISTRY_KEY_CELL_NOT_ALLOCATED is returned if the key cell is not allocated. CM_CHECK_REGISTRY_CELL_DATA_NOT_FOUND is returned if cell data could not be mapped from the key cell. CM_CHECK_REGISTRY_CELL_SIZE_NOT_SANE is returned if the key cell has an abnormal size that is above the trehshold the validation checks can permit. CM_CHECK_REGISTRY_KEY_NAME_LENGTH_ZERO is returned if the name length of the key node is 0, meaning that the key has no name. CM_CHECK_REGISTRY_KEY_TOO_BIG_THAN_CELL is returned if the key is too big than the cell itself. CM_CHECK_REGISTRY_BAD_KEY_NODE_PARENT is returned if the parent node of the key is incosistent and it couldn't be fixed. CM_CHECK_REGISTRY_BAD_KEY_NODE_SIGNATURE is returned if the signature of the key node is corrupt and it couldn't be fixed. A failure CM status code is returned otherwise.

Definition at line 939 of file cmcheck.c.

946{
947 CM_CHECK_REGISTRY_STATUS CmStatusCode;
948 PCELL_DATA CellData;
949 ULONG CellSize;
950 BOOLEAN DoSubkeysRepair;
951 ULONG TotalKeyNameLength, NameLength;
952
953 PAGED_CODE();
954
955 /* The current key cell mustn't be NIL here! */
956 ASSERT(CurrentCell != HCELL_NIL);
957
958 /* TODO: To be removed once we support security caching in Cm */
959 UNREFERENCED_PARAMETER(SecurityDefaulted);
960
961 /*
962 * We must ensure that the key cell is
963 * allocated in the first place before
964 * we go further.
965 */
966 if (!HvIsCellAllocated(Hive, CurrentCell))
967 {
968 DPRINT1("The key cell is not allocated\n");
970 }
971
972 /* Obtain cell data from it */
973 CellData = (PCELL_DATA)HvGetCell(Hive, CurrentCell);
974 if (!CellData)
975 {
976 DPRINT1("Could not get cell data from the cell\n");
978 }
979
980 /* Get the size of this cell and validate its size */
981 CellSize = HvGetCellSize(Hive, CellData);
982 if (CellSize > CMP_KEY_SIZE_THRESHOLD)
983 {
984 DPRINT1("The cell size is above the threshold size (size %u)\n", CellSize);
986 }
987
988 /*
989 * The cell size is OK but we must ensure
990 * the key is not bigger than the container
991 * of the cell.
992 */
993 NameLength = CellData->u.KeyNode.NameLength;
994 if (NameLength == 0)
995 {
996 DPRINT1("The key node name length is 0!\n");
998 }
999
1000 TotalKeyNameLength = NameLength + FIELD_OFFSET(CM_KEY_NODE, Name);
1001 if (TotalKeyNameLength > CellSize)
1002 {
1003 DPRINT1("The key is too big than the cell (key size %u, cell size %u)\n",
1004 TotalKeyNameLength, CellSize);
1006 }
1007
1008 /* Is the parent cell consistent? */
1009 if (ParentCell != HCELL_NIL &&
1010 ParentCell != CellData->u.KeyNode.Parent)
1011 {
1012 if (!CmpRepairParentNode(Hive,
1013 CurrentCell,
1014 ParentCell,
1015 CellData,
1016 FixHive))
1017 {
1018 DPRINT1("The parent key node doesn't point to the actual parent\n");
1020 }
1021 }
1022
1023 /* Is the key node signature valid? */
1024 if (CellData->u.KeyNode.Signature != CM_KEY_NODE_SIGNATURE)
1025 {
1026 if (!CmpRepairKeyNodeSignature(Hive,
1027 CurrentCell,
1028 CellData,
1029 FixHive))
1030 {
1031 DPRINT1("The parent key node signature is not valid\n");
1033 }
1034 }
1035
1036 /*
1037 * FIXME: Security cell checks have to be implemented here
1038 * once we properly and reliably implement security caching
1039 * in the kernel.
1040 */
1041
1042 /* Validate the class */
1043 CmStatusCode = CmpValidateClass(Hive, CurrentCell, CellData);
1044 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1045 {
1046 if (!CmpRepairClassOfNodeKey(Hive,
1047 CurrentCell,
1048 CellData,
1049 FixHive))
1050 {
1051 DPRINT1("Failed to repair the hive, the cell class is not valid\n");
1052 return CmStatusCode;
1053 }
1054 }
1055
1056 /* Validate the value list */
1057 CmStatusCode = CmpValidateValueList(Hive, CurrentCell, CellData, FixHive);
1058 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1059 {
1060 /*
1061 * It happens that a certain value in the list
1062 * is so bad like we couldn't map a cell data from it
1063 * or the list itself is toast. In such cases what we
1064 * can do here is to do a "value list sacrifice", aka
1065 * purge the whole list.
1066 */
1067 if (!CmpRepairValueList(Hive, CurrentCell, FixHive))
1068 {
1069 DPRINT1("Failed to repair the hive, the value list is corrupt\n");
1070 return CmStatusCode;
1071 }
1072 }
1073
1074 /* Validate the subkeys list */
1075 CmStatusCode = CmpValidateSubKeyList(Hive, CurrentCell, CellData, FixHive, &DoSubkeysRepair);
1076 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1077 {
1078 /*
1079 * The subkeys list is in trouble. Worse when the actual
1080 * subkey list is so severed this key is also kaput on itself.
1081 */
1082 if (!DoSubkeysRepair)
1083 {
1084 DPRINT1("The subkeys list is totally corrupt, can't repair\n");
1085 return CmStatusCode;
1086 }
1087
1088 /*
1089 * OK, there's still some salvation for this key.
1090 * Purge the whole subkeys list in order to fix it.
1091 */
1092 if (!CmpRepairSubKeyList(Hive,
1093 CurrentCell,
1094 CellData,
1095 FixHive))
1096 {
1097 DPRINT1("Failed to repair the hive, the subkeys list is corrupt!\n");
1098 return CmStatusCode;
1099 }
1100 }
1101
1102 /* Purge volatile data if needed */
1103 CmpPurgeVolatiles(Hive, CurrentCell, CellData, Flags);
1105}
#define CMP_KEY_SIZE_THRESHOLD
Definition: cmcheck.c:38
static VOID CmpPurgeVolatiles(_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ ULONG Flags)
Purges the volatile storage of a registry hive. This operation is done mainly during the bootup of th...
Definition: cmcheck.c:849
static CM_CHECK_REGISTRY_STATUS CmpValidateSubKeyList(_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive, _Out_ PBOOLEAN DoRepair)
Validates the subkeys list of a key. If the list is damaged from corruption, the function can either ...
Definition: cmcheck.c:644
static CM_CHECK_REGISTRY_STATUS CmpValidateClass(_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData)
Validates the class of a given key cell.
Definition: cmcheck.c:190
static CM_CHECK_REGISTRY_STATUS CmpValidateValueList(_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Validates the value list of a key. If the list is damaged due to corruption, the whole list is expung...
Definition: cmcheck.c:508
struct _CELL_DATA * PCELL_DATA
#define CM_KEY_NODE_SIGNATURE
Definition: cmdata.h:21
BOOLEAN CMAPI CmpRepairValueList(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ BOOLEAN FixHive)
Repairs the value list due to corruption. The process involes by purging the whole damaged list.
Definition: cmheal.c:766
BOOLEAN CMAPI CmpRepairClassOfNodeKey(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Repairs the class from damage due to class corruption within the node key.
Definition: cmheal.c:638
BOOLEAN CMAPI CmpRepairParentNode(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ HCELL_INDEX ParentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Repairs the parent of the node from damage due to parent cell and parent node incosistency.
Definition: cmheal.c:533
BOOLEAN CMAPI CmpRepairKeyNodeSignature(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Repairs the key node signature from damage due to signature corruption.
Definition: cmheal.c:586
BOOLEAN CMAPI CmpRepairSubKeyList(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Repairs the subkey list due to corruption. The process involves by purging the whole damaged subkeys ...
Definition: cmheal.c:884
#define CM_CHECK_REGISTRY_CELL_SIZE_NOT_SANE
Definition: cmlib.h:253
#define CM_CHECK_REGISTRY_KEY_TOO_BIG_THAN_CELL
Definition: cmlib.h:255
#define CM_CHECK_REGISTRY_KEY_NAME_LENGTH_ZERO
Definition: cmlib.h:254
#define CM_CHECK_REGISTRY_BAD_KEY_NODE_PARENT
Definition: cmlib.h:256
#define CM_CHECK_REGISTRY_KEY_CELL_NOT_ALLOCATED
Definition: cmlib.h:251
LONG CMAPI HvGetCellSize(PHHIVE RegistryHive, PVOID Cell)
#define CM_CHECK_REGISTRY_BAD_KEY_NODE_SIGNATURE
Definition: cmlib.h:257
#define HvGetCell(Hive, Cell)
Definition: cmlib.h:457
#define CM_CHECK_REGISTRY_CELL_DATA_NOT_FOUND
Definition: cmlib.h:252
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
union _CELL_DATA::@4304 u
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
USHORT Signature
Definition: cmdata.h:92
HCELL_INDEX Parent
Definition: cmdata.h:96
USHORT NameLength
Definition: cmdata.h:114
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255

Referenced by CmpValidateRegistryInternal().

◆ CmpValidateLexicalOrder()

static BOOLEAN CmpValidateLexicalOrder ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  Child,
_In_ HCELL_INDEX  Sibling 
)
static

Validates the lexicographical order between a child and prior sibling of the said child.

Parameters
[in]HiveA pointer to a hive descriptor of which lexicographical order of keys are to be checked.
[in]ChildA child subkey cell used for lexicographical order validation checks.
[in]SiblingA subkey cell which is the prior sibling of the child. This is used in conjuction with the child to perfrom lexical order checks.
Returns
Returns TRUE if the order is legal, FALSE otherwise.

Definition at line 66 of file cmcheck.c.

70{
72 UNICODE_STRING ChildString, SiblingString;
73 PCM_KEY_NODE ChildNode, SiblingNode;
74
75 PAGED_CODE();
76
77 /* Obtain the child node */
78 ChildNode = (PCM_KEY_NODE)HvGetCell(Hive, Child);
79 if (!ChildNode)
80 {
81 /* Couldn't get the child node, bail out */
82 DPRINT1("Failed to get the child node\n");
83 return FALSE;
84 }
85
86 /* Obtain the sibling node */
87 SiblingNode = (PCM_KEY_NODE)HvGetCell(Hive, Sibling);
88 if (!SiblingNode)
89 {
90 /* Couldn't get the sibling node, bail out */
91 DPRINT1("Failed to get the sibling node\n");
92 return FALSE;
93 }
94
95 /* CASE 1: Two distinct non-compressed Unicode names */
96 if ((ChildNode->Flags & KEY_COMP_NAME) == 0 &&
97 (SiblingNode->Flags & KEY_COMP_NAME) == 0)
98 {
99 /* Build the sibling string */
100 SiblingString.Buffer = &(SiblingNode->Name[0]);
101 SiblingString.Length = SiblingNode->NameLength;
102 SiblingString.MaximumLength = SiblingNode->NameLength;
103
104 /* Build the child string */
105 ChildString.Buffer = &(ChildNode->Name[0]);
106 ChildString.Length = ChildNode->NameLength;
107 ChildString.MaximumLength = ChildNode->NameLength;
108
109 Result = RtlCompareUnicodeString(&SiblingString, &ChildString, TRUE);
110 if (Result >= 0)
111 {
112 DPRINT1("The sibling node name is greater or equal to that of the child\n");
113 return FALSE;
114 }
115 }
116
117 /* CASE 2: Both compressed Unicode names */
118 if ((ChildNode->Flags & KEY_COMP_NAME) &&
119 (SiblingNode->Flags & KEY_COMP_NAME))
120 {
121 /* FIXME: Checks for two compressed names not implemented yet */
122 DPRINT("Lexicographical order checks for two compressed names is UNIMPLEMENTED, assume the key is healthy...\n");
123 return TRUE;
124 }
125
126 /* CASE 3: The child name is compressed but the sibling is not */
127 if ((ChildNode->Flags & KEY_COMP_NAME) &&
128 (SiblingNode->Flags & KEY_COMP_NAME) == 0)
129 {
130 SiblingString.Buffer = &(SiblingNode->Name[0]);
131 SiblingString.Length = SiblingNode->NameLength;
132 SiblingString.MaximumLength = SiblingNode->NameLength;
133 Result = CmpCompareCompressedName(&SiblingString,
134 ChildNode->Name,
135 ChildNode->NameLength);
136 if (Result >= 0)
137 {
138 DPRINT1("The sibling node name is greater or equal to that of the compressed child\n");
139 return FALSE;
140 }
141 }
142
143 /* CASE 4: The sibling name is compressed but the child is not */
144 if ((SiblingNode->Flags & KEY_COMP_NAME) &&
145 (ChildNode->Flags & KEY_COMP_NAME) == 0)
146 {
147 ChildString.Buffer = &(ChildNode->Name[0]);
148 ChildString.Length = ChildNode->NameLength;
149 ChildString.MaximumLength = ChildNode->NameLength;
150 Result = CmpCompareCompressedName(&ChildString,
151 SiblingNode->Name,
152 SiblingNode->NameLength);
153 if (Result <= 0)
154 {
155 DPRINT1("The compressed sibling node name is lesser or equal to that of the child\n");
156 return FALSE;
157 }
158 }
159
160 /*
161 * One of the cases above has met the conditions
162 * successfully, the lexicographical order is legal.
163 */
164 return TRUE;
165}
struct _CM_KEY_NODE * PCM_KEY_NODE
#define KEY_COMP_NAME
Definition: cmdata.h:35
LONG NTAPI CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, IN PWCHAR CompressedName, IN ULONG NameLength)
Definition: cmname.c:109
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
long LONG
Definition: pedump.c:60
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
USHORT Flags
Definition: cmdata.h:93
USHORT MaximumLength
Definition: env_spec_w32.h:370
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFDEVICE Child
Definition: wdffdo.h:536
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

Referenced by CmpValidateRegistryInternal().

◆ CmpValidateRegistryInternal()

static CM_CHECK_REGISTRY_STATUS CmpValidateRegistryInternal ( _In_ PHHIVE  Hive,
_In_ ULONG  Flags,
_In_ BOOLEAN  SecurityDefaulted,
_In_ BOOLEAN  FixHive 
)
static

Performs deep checking of the registry by walking down the registry tree using a stack based pool. This function is the guts of CmCheckRegistry.

Parameters
[in]HiveA pointer to a hive descriptor of the registry where the validation is to be performed.
[in]FlagsBit mask flag used for volatiles purging. Such flags influence on how volatile purging is actually done. See CmCheckRegistry documentation for more information.
[in]SecurityDefaultedIf the caller sets this to FALSE, the registry hive uses its own unique security details. Otherwise registry hive has the security details defaulted.
[in]FixHiveIf set to TRUE, the target hive will be fixed.
Returns
Returns CM_CHECK_REGISTRY_GOOD is returned if the function has successfully performed deep registry checking and the registry contents are valid. CM_CHECK_REGISTRY_ALLOCATE_MEM_STACK_FAIL is returned if the function has failed to allocate the stack work state buffer in memory which is necessary for deep checking of the registry. CM_CHECK_REGISTRY_ROOT_CELL_NOT_FOUND is returned if no root cell has been found of this hive. CM_CHECK_REGISTRY_BAD_LEXICOGRAPHICAL_ORDER is returned if the lexical order is not valid. CM_CHECK_REGISTRY_NODE_NOT_FOUND is returned if the no key node could be mapped from the key. CM_CHECK_REGISTRY_SUBKEY_NOT_FOUND is returned if no subkey child cell could be found. CM_CHECK_REGISTRY_TREE_TOO_MANY_LEVELS is returned if we have reached the maximum stack limit which means the registry that we have checked is too fat.

Definition at line 1148 of file cmcheck.c.

1153{
1154 CM_CHECK_REGISTRY_STATUS CmStatusCode;
1156 HCELL_INDEX RootCell, ParentCell, CurrentCell;
1157 HCELL_INDEX ChildSubKeyCell;
1158 PCM_KEY_NODE KeyNode;
1159 ULONG WorkStateLength;
1160 LONG StackDepth;
1161 BOOLEAN AllChildrenChecked;
1162
1163 PAGED_CODE();
1164
1165 ASSERT(Hive);
1166
1167 /*
1168 * Allocate some memory blocks for the stack
1169 * state structure. We'll be using it to walk
1170 * down the registry hive tree in a recursive
1171 * way without worrying that we explode the
1172 * kernel stack in the most gruesome and gross
1173 * ways.
1174 */
1176 WorkState = CmpAllocate(WorkStateLength,
1177 TRUE,
1179 if (!WorkState)
1180 {
1181 DPRINT1("Couldn't allocate memory for registry stack work state\n");
1183 }
1184
1185 /* Obtain the root cell of the hive */
1186 RootCell = GET_HHIVE_ROOT_CELL(Hive);
1187 if (RootCell == HCELL_NIL)
1188 {
1189 DPRINT1("Couldn't get the root cell of the hive\n");
1190 CmpFree(WorkState, WorkStateLength);
1192 }
1193
1194RestartValidation:
1195 /*
1196 * Prepare the stack state and start from
1197 * the root cell. Ensure that the root cell
1198 * itself is OK before we go forward.
1199 */
1200 StackDepth = 0;
1201 WorkState[StackDepth].ChildCellIndex = 0;
1202 WorkState[StackDepth].Current = RootCell;
1203 WorkState[StackDepth].Parent = HCELL_NIL;
1204 WorkState[StackDepth].Sibling = HCELL_NIL;
1205
1206 /*
1207 * As we start checking the root cell which
1208 * is the top element of a registry hive,
1209 * we'll be going to look for child keys
1210 * in the course of walking down the tree.
1211 */
1212 AllChildrenChecked = FALSE;
1213
1214 while (StackDepth >= 0)
1215 {
1216 /* Cache the current and parent cells */
1217 CurrentCell = WorkState[StackDepth].Current;
1218 ParentCell = WorkState[StackDepth].Parent;
1219
1220 /* Do we have still have children to validate? */
1221 if (!AllChildrenChecked)
1222 {
1223 /* Check that the key is OK */
1224 CmStatusCode = CmpValidateKey(Hive,
1225 SecurityDefaulted,
1226 ParentCell,
1227 CurrentCell,
1228 Flags,
1229 FixHive);
1230 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1231 {
1232 /*
1233 * The key cell is damaged. We have to pray and
1234 * hope that this is not the root cell as any
1235 * damage done to the root is catastrophically
1236 * fatal.
1237 */
1238 if (CurrentCell == RootCell)
1239 {
1240 DPRINT1("THE ROOT CELL IS BROKEN\n");
1241 CmpFree(WorkState, WorkStateLength);
1242 return CmStatusCode;
1243 }
1244
1245 /*
1246 * It is not the root, remove the faulting
1247 * damaged cell from the parent so that we
1248 * can heal the hive.
1249 */
1250 if (!CmpRepairParentKey(Hive, CurrentCell, ParentCell, FixHive))
1251 {
1252 DPRINT1("The key is corrupt (current cell 0x%x, parent cell 0x%x)\n",
1253 CurrentCell, ParentCell);
1254 CmpFree(WorkState, WorkStateLength);
1255 return CmStatusCode;
1256 }
1257
1258 /* Damaged cell removed, restart the loop */
1259 DPRINT1("Hive repaired, restarting the validation loop...\n");
1260 goto RestartValidation;
1261 }
1262
1263 /*
1264 * The key is in perfect shape. If we have advanced
1265 * the stack depth then check the lexicographical
1266 * order of the keys as well.
1267 */
1268 if (StackDepth > 0 &&
1269 CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1270 {
1271 if (WorkState[StackDepth - CMP_PRIOR_STACK].Sibling != HCELL_NIL)
1272 {
1273 if (!CmpValidateLexicalOrder(Hive,
1274 CurrentCell,
1275 WorkState[StackDepth - CMP_PRIOR_STACK].Sibling))
1276 {
1277 /*
1278 * The lexicographical order is bad,
1279 * attempt to heal the hive.
1280 */
1281 if (!CmpRepairParentKey(Hive, CurrentCell, ParentCell, FixHive))
1282 {
1283 DPRINT1("The lexicographical order is invalid (sibling 0x%x, current cell 0x%x)\n",
1284 CurrentCell, WorkState[StackDepth - CMP_PRIOR_STACK].Sibling);
1285 CmpFree(WorkState, WorkStateLength);
1287 }
1288
1289 /* Damaged cell removed, restart the loop */
1290 DPRINT1("Hive repaired, restarting the validation loop...\n");
1291 goto RestartValidation;
1292 }
1293 }
1294
1295 /* Assign the prior sibling for upcoming iteration */
1296 WorkState[StackDepth - CMP_PRIOR_STACK].Sibling = CurrentCell;
1297 }
1298 }
1299
1300 /* Obtain a node for this key */
1301 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell);
1302 if (!KeyNode)
1303 {
1304 DPRINT1("Couldn't get the node of key (current cell 0x%x)\n", CurrentCell);
1305 CmpFree(WorkState, WorkStateLength);
1307 }
1308
1309 /*
1310 * If we have processed all the children from this
1311 * node then adjust the stack depth work state by
1312 * going back and restart the loop to lookup for
1313 * the rest of the tree. Acknowledge the code path
1314 * above that we checked all the children so that
1315 * we don't have to validate the same subkey again.
1316 */
1317 if (WorkState[StackDepth].ChildCellIndex < KeyNode->SubKeyCounts[Stable])
1318 {
1319 /*
1320 * We have children to process, obtain the
1321 * child subkey in question so that we can
1322 * cache it later for the next key validation.
1323 */
1324 ChildSubKeyCell = CmpFindSubKeyByNumber(Hive, KeyNode, WorkState[StackDepth].ChildCellIndex);
1325 if (ChildSubKeyCell == HCELL_NIL)
1326 {
1327 DPRINT1("Couldn't get the child subkey cell (at stack index %d)\n", StackDepth);
1328 CmpFree(WorkState, WorkStateLength);
1330 }
1331
1332 /*
1333 * As we got the subkey advance the child index as
1334 * well as the stack depth work state for the next
1335 * key validation. However we must ensure since
1336 * we're advancing the stack depth that we don't
1337 * go over the maximum tree level depth. A registry
1338 * tree can be at maximum 512 levels deep.
1339 *
1340 * For more information see https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits.
1341 */
1342 WorkState[StackDepth].ChildCellIndex++;
1343 StackDepth++;
1344 if (StackDepth >= CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH - 1)
1345 {
1346 /*
1347 * This registry has so many levels it's
1348 * so fat. We don't want to explode our
1349 * kernel stack, so just simply bail out...
1350 */
1351 DPRINT1("The registry tree has so many levels!\n");
1352 CmpFree(WorkState, WorkStateLength);
1354 }
1355
1356 /* Prepare the work state for the next key */
1357 WorkState[StackDepth].ChildCellIndex = 0;
1358 WorkState[StackDepth].Current = ChildSubKeyCell;
1359 WorkState[StackDepth].Parent = WorkState[StackDepth - CMP_PRIOR_STACK].Current;
1360 WorkState[StackDepth].Sibling = HCELL_NIL;
1361
1362 /*
1363 * As we prepared the work state, acknowledge the
1364 * code path at the top of the loop that we need
1365 * to process and validate the next child subkey.
1366 */
1367 AllChildrenChecked = FALSE;
1368 continue;
1369 }
1370
1371 /*
1372 * We have validated all the child subkeys
1373 * of the node. Decrease the stack depth
1374 * and tell the above code we looked for all
1375 * children so that we don't need to validate
1376 * the same children again but go for the next
1377 * node.
1378 */
1379 AllChildrenChecked = TRUE;
1380 StackDepth--;
1381 continue;
1382 }
1383
1384 CmpFree(WorkState, WorkStateLength);
1386}
PVOID NTAPI CmpAllocate(_In_ SIZE_T Size, _In_ BOOLEAN Paged, _In_ ULONG Tag)
Definition: bootreg.c:90
VOID NTAPI CmpFree(_In_ PVOID Ptr, _In_ ULONG Quota)
Definition: bootreg.c:105
static BOOLEAN CmpValidateLexicalOrder(_In_ PHHIVE Hive, _In_ HCELL_INDEX Child, _In_ HCELL_INDEX Sibling)
Validates the lexicographical order between a child and prior sibling of the said child.
Definition: cmcheck.c:66
static CM_CHECK_REGISTRY_STATUS CmpValidateKey(_In_ PHHIVE Hive, _In_ BOOLEAN SecurityDefaulted, _In_ HCELL_INDEX ParentCell, _In_ HCELL_INDEX CurrentCell, _In_ ULONG Flags, _In_ BOOLEAN FixHive)
Validates the key cell, ensuring that the key in the registry is valid and not corrupted.
Definition: cmcheck.c:939
#define CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH
Definition: cmcheck.c:36
struct _CMP_REGISTRY_STACK_WORK_STATE CMP_REGISTRY_STACK_WORK_STATE
#define GET_HHIVE_ROOT_CELL(Hive)
Definition: cmcheck.c:25
#define CMP_PRIOR_STACK
Definition: cmcheck.c:35
BOOLEAN CMAPI CmpRepairParentKey(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX TargetKey, _In_ HCELL_INDEX ParentKey, _In_ BOOLEAN FixHive)
Repairs the parent key from damage by removing the offending subkey cell.
Definition: cmheal.c:409
HCELL_INDEX NTAPI CmpFindSubKeyByNumber(IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN ULONG Number)
Definition: cmindex.c:600
#define CM_CHECK_REGISTRY_ROOT_CELL_NOT_FOUND
Definition: cmlib.h:246
#define CM_CHECK_REGISTRY_BAD_LEXICOGRAPHICAL_ORDER
Definition: cmlib.h:247
#define CM_CHECK_REGISTRY_NODE_NOT_FOUND
Definition: cmlib.h:248
#define CM_CHECK_REGISTRY_ALLOCATE_MEM_STACK_FAIL
Definition: cmlib.h:245
#define TAG_REGISTRY_STACK
Definition: cmlib.h:216
#define CM_CHECK_REGISTRY_SUBKEY_NOT_FOUND
Definition: cmlib.h:249
#define CM_CHECK_REGISTRY_TREE_TOO_MANY_LEVELS
Definition: cmlib.h:250
@ Stable
Definition: hivedata.h:127

Referenced by CmCheckRegistry().

◆ CmpValidateSubKeyList()

static CM_CHECK_REGISTRY_STATUS CmpValidateSubKeyList ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  CurrentCell,
_Inout_ PCELL_DATA  CellData,
_In_ BOOLEAN  FixHive,
_Out_ PBOOLEAN  DoRepair 
)
static

Validates the subkeys list of a key. If the list is damaged from corruption, the function can either salvage this list or purge the whole of it. The function performs different validation steps for different storage types.

Parameters
[in]HiveA pointer to a hive descriptor of which a list of subkeys is to be validated.
[in]CurrentCellThe current key cell that the subkeys list points to.
[in]CellDataThe cell data of the current cell of which the subkeys list comes from.
[in]FixHiveIf set to TRUE, the target hive will be fixed.
[out]DoRepairA pointer to a boolean value set up by the function itself. The function automatically sets this to FALSE indicating that repairs can't be done onto the list itself. If the list can be salvaged, then the function sets this to TRUE. See Remarks for further information.
Returns
Returns CM_CHECK_REGISTRY_GOOD if the subkeys list is in perfect shape. CM_CHECK_REGISTRY_STABLE_KEYS_ON_VOLATILE is returned if the volatile storage has stable data which that should not happen (this is only for the case of volatile cells). CM_CHECK_REGISTRY_SUBKEYS_LIST_UNALLOCATED is returned if the subkeys list cell is not allocated. CM_CHECK_REGISTRY_CORRUPT_SUBKEYS_INDEX is returned if a key index could not be mapped from the subkeys list cell. CM_CHECK_REGISTRY_BAD_SUBKEY_COUNT is returned if the key index is a leaf and the subkeys count doesn't match up with that of the leaf. CM_CHECK_REGISTRY_KEY_INDEX_CELL_UNALLOCATED is returned if the key index cell at the specific index in the list of the index is not allocated. CM_CHECK_REGISTRY_CORRUPT_LEAF_ON_ROOT is returned if a leaf could not be mapped from an index. CM_CHECK_REGISTRY_CORRUPT_LEAF_SIGNATURE is returned if the leaf has an invalid signature. CM_CHECK_REGISTRY_CORRUPT_KEY_INDEX_SIGNATURE is returned if the key index has an invalid signature, that is, it's not a leaf nor a root.
Remarks
Deep subkeys list healing can be done in specific cases where only a subkey doesn't actually affect the key itself. The function will mark the subkeys list as repairable by setting DoRepair parameter to TRUE and the caller is responsible to heal the key by purging the whole subkeys list. If the damage is so bad that there's possibility the key itself is even damaged, no healing is done.

Definition at line 644 of file cmcheck.c.

650{
651 ULONG SubKeyCounts;
652 HCELL_INDEX KeyIndexCell, SubKeysListCell;
653 PCM_KEY_INDEX RootKeyIndex, LeafKeyIndex;
654 ULONG RootIndex;
655 ULONG TotalLeafCount;
656
657 PAGED_CODE();
658
659 ASSERT(CurrentCell != HCELL_NIL);
660 ASSERT(CellData);
661
662 RootKeyIndex = NULL;
663 LeafKeyIndex = NULL;
664 TotalLeafCount = 0;
665
666 /*
667 * Assume for now that the caller should not
668 * do any kind of repairs on the subkeys list,
669 * unless explicitly given the consent by us.
670 */
671 *DoRepair = FALSE;
672
673 /*
674 * For volatile keys they have data that can
675 * fluctuate and change on the fly so there's
676 * pretty much nothing that we can validate those.
677 * But still, we would want that the volatile key
678 * is not damaged by external factors, like e.g.,
679 * having stable keys on a volatile space.
680 */
681 if (IS_CELL_VOLATILE(CurrentCell))
682 {
683 if (CellData->u.KeyNode.SubKeyCounts[Stable] != 0)
684 {
685 DPRINT1("The volatile key has stable subkeys\n");
687 }
688
690 }
691
692 /*
693 * This is not a volatile key, cache the subkeys list
694 * and validate it.
695 */
696 SubKeysListCell = CellData->u.KeyNode.SubKeyLists[Stable];
697 SubKeyCounts = CellData->u.KeyNode.SubKeyCounts[Stable];
698 if (SubKeyCounts > 0)
699 {
700 if (!HvIsCellAllocated(Hive, SubKeysListCell))
701 {
702 DPRINT1("The subkeys list cell is not allocated\n");
703 *DoRepair = TRUE;
705 }
706
707 /* Obtain a root index and validate it */
708 RootKeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, SubKeysListCell);
709 if (!RootKeyIndex)
710 {
711 DPRINT1("Could not get the root key index of the subkeys list cell\n");
713 }
714
715 /*
716 * For simple, fast and hashed leaves we would want
717 * that the corresponding root index count matches with
718 * that of the subkey counts itself. If this is not the
719 * case we can isolate this problem and fix the count.
720 */
721 if (RootKeyIndex->Signature == CM_KEY_INDEX_LEAF ||
722 RootKeyIndex->Signature == CM_KEY_FAST_LEAF ||
723 RootKeyIndex->Signature == CM_KEY_HASH_LEAF)
724 {
725 if (SubKeyCounts != RootKeyIndex->Count)
726 {
727 if (!CmpRepairSubKeyCounts(Hive,
728 CurrentCell,
729 RootKeyIndex->Count,
730 CellData,
731 FixHive))
732 {
733 DPRINT1("The subkeys list has invalid count (subkeys count %u, root key index count %u)\n",
734 SubKeyCounts, RootKeyIndex->Count);
736 }
737 }
738
740 }
741
742 /*
743 * The root index is not a leaf, check if the index
744 * is an actual root then.
745 */
746 if (RootKeyIndex->Signature == CM_KEY_INDEX_ROOT)
747 {
748 /*
749 * For the root we have to loop each leaf
750 * from it and increase the total leaf count
751 * in the root after we determined the validity
752 * of a leaf. This way we can see if the subcount
753 * matches with that of the subkeys list count.
754 */
755 for (RootIndex = 0; RootIndex < RootKeyIndex->Count; RootIndex++)
756 {
757 KeyIndexCell = RootKeyIndex->List[RootIndex];
758 if (!HvIsCellAllocated(Hive, KeyIndexCell))
759 {
760 DPRINT1("The key index cell is not allocated at index %u\n", RootIndex);
761 *DoRepair = TRUE;
763 }
764
765 /* Obtain a leaf from the root */
766 LeafKeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, KeyIndexCell);
767 if (!LeafKeyIndex)
768 {
769 DPRINT1("The root key index's signature is invalid!\n");
771 }
772
773 /* Check that the leaf has valid signature */
774 if (LeafKeyIndex->Signature != CM_KEY_INDEX_LEAF &&
775 LeafKeyIndex->Signature != CM_KEY_FAST_LEAF &&
776 LeafKeyIndex->Signature != CM_KEY_HASH_LEAF)
777 {
778 DPRINT1("The leaf's signature is invalid!\n");
779 *DoRepair = TRUE;
781 }
782
783 /* Add up the count of the leaf */
784 TotalLeafCount += LeafKeyIndex->Count;
785 }
786
787 /*
788 * We have built up the total leaf count,
789 * we have to determine this count is exactly
790 * the same as the subkeys list count. Otherwise
791 * just fix it.
792 */
793 if (SubKeyCounts != TotalLeafCount)
794 {
795 if (!CmpRepairSubKeyCounts(Hive,
796 CurrentCell,
797 TotalLeafCount,
798 CellData,
799 FixHive))
800 {
801 DPRINT1("The subkeys list has invalid count (subkeys count %u, total leaf count %u)\n",
802 SubKeyCounts, TotalLeafCount);
804 }
805 }
806
808 }
809
810 /*
811 * None of the valid signatures match with that of
812 * the root key index. By definition, the whole subkey
813 * list is total toast.
814 */
815 DPRINT1("The root key index's signature is invalid\n");
816 *DoRepair = TRUE;
818 }
819
820 /* If we reach here then this key has no subkeys */
822}
#define IS_CELL_VOLATILE(Cell)
Definition: cmcheck.c:29
#define CM_KEY_INDEX_LEAF
Definition: cmdata.h:14
#define CM_KEY_INDEX_ROOT
Definition: cmdata.h:13
#define CM_KEY_FAST_LEAF
Definition: cmdata.h:15
struct _CM_KEY_INDEX * PCM_KEY_INDEX
#define CM_KEY_HASH_LEAF
Definition: cmdata.h:16
BOOLEAN CMAPI CmpRepairSubKeyCounts(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ ULONG Count, _Inout_ PCELL_DATA CellData, _In_ BOOLEAN FixHive)
Repairs the subkey list count due to corruption. The process involves by fixing the count itself with...
Definition: cmheal.c:830
#define CM_CHECK_REGISTRY_BAD_SUBKEY_COUNT
Definition: cmlib.h:272
#define CM_CHECK_REGISTRY_STABLE_KEYS_ON_VOLATILE
Definition: cmlib.h:269
#define CM_CHECK_REGISTRY_KEY_INDEX_CELL_UNALLOCATED
Definition: cmlib.h:273
#define CM_CHECK_REGISTRY_CORRUPT_LEAF_ON_ROOT
Definition: cmlib.h:274
#define CM_CHECK_REGISTRY_CORRUPT_LEAF_SIGNATURE
Definition: cmlib.h:275
#define CM_CHECK_REGISTRY_CORRUPT_SUBKEYS_INDEX
Definition: cmlib.h:271
#define CM_CHECK_REGISTRY_SUBKEYS_LIST_UNALLOCATED
Definition: cmlib.h:270
#define CM_CHECK_REGISTRY_CORRUPT_KEY_INDEX_SIGNATURE
Definition: cmlib.h:276
#define NULL
Definition: types.h:112
USHORT Signature
Definition: cmdata.h:178
USHORT Count
Definition: cmdata.h:179
HCELL_INDEX List[ANYSIZE_ARRAY]
Definition: cmdata.h:180

Referenced by CmpValidateKey().

◆ CmpValidateValueList()

static CM_CHECK_REGISTRY_STATUS CmpValidateValueList ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  CurrentCell,
_Inout_ PCELL_DATA  CellData,
_In_ BOOLEAN  FixHive 
)
static

Validates the value list of a key. If the list is damaged due to corruption, the whole list is expunged. This function performs self-healing procedures in this case.

Parameters
[in]HiveA pointer to a hive descriptor of which a list of registry values is to be validated.
[in]CurrentCellThe current key cell that the value list points to.
[in]CellDataThe cell data of the current cell of which the value list comes from.
[in]FixHiveIf set to TRUE, the target hive will be fixed.
Returns
Returns CM_CHECK_REGISTRY_GOOD if the value list is sane. CM_CHECK_REGISTRY_VALUE_LIST_UNALLOCATED is returned if the value list cell is not allocated. CM_CHECK_REGISTRY_VALUE_LIST_DATA_NOT_FOUND is returned if cell data could not be mapped from the value list cell. CM_CHECK_REGISTRY_VALUE_LIST_SIZE_NOT_SANE is returned if the size of the value list is bogus. A failure CM status code is returned otherwise.

Definition at line 508 of file cmcheck.c.

513{
514 CM_CHECK_REGISTRY_STATUS CmStatusCode;
515 ULONG TotalValueLength, ValueSize;
516 ULONG ValueListCount;
517 ULONG ValuesRemoved;
518 HCELL_INDEX ValueListCell;
519 PCELL_DATA ValueListData;
520
521 PAGED_CODE();
522
523 ASSERT(CurrentCell != HCELL_NIL);
524 ASSERT(CellData);
525
526 /* Cache the value list and validate it */
527 ValueListCell = CellData->u.KeyNode.ValueList.List;
528 ValueListCount = CellData->u.KeyNode.ValueList.Count;
529 if (ValueListCount > 0)
530 {
531 if (!HvIsCellAllocated(Hive, ValueListCell))
532 {
533 DPRINT1("The value list is not allocated\n");
535 }
536
537 /* Obtain cell data from the value list cell */
538 ValueListData = (PCELL_DATA)HvGetCell(Hive, ValueListCell);
539 if (!ValueListData)
540 {
541 DPRINT1("Could not get cell data from the value list\n");
543 }
544
545 /*
546 * Cache the value size and total length and
547 * assert ourselves this is a sane value list
548 * to begin with.
549 */
550 ValueSize = HvGetCellSize(Hive, ValueListData);
551 TotalValueLength = ValueListCount * sizeof(HCELL_INDEX);
552 if (TotalValueLength > ValueSize)
553 {
554 DPRINT1("The value list is bigger than the cell (value list size %u, cell size %u)\n",
555 TotalValueLength, ValueSize);
557 }
558
559 /*
560 * The value list is sane, now we would
561 * need to validate the actual list
562 * by its count.
563 */
564 CmStatusCode = CmpValidateValueListByCount(Hive,
565 CurrentCell,
566 ValueListCount,
567 ValueListData,
568 &ValuesRemoved,
569 FixHive);
570 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
571 {
572 DPRINT1("One of the values is corrupt and couldn't be repaired\n");
573 return CmStatusCode;
574 }
575
576 /* Log how much values have been removed */
577 if (ValuesRemoved > 0)
578 {
579 DPRINT1("%u values removed in the list\n", ValuesRemoved);
580 }
581 }
582
584}
static CM_CHECK_REGISTRY_STATUS CmpValidateValueListByCount(_In_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ ULONG ListCount, _In_ PCELL_DATA ValueListData, _Out_ PULONG ValuesRemoved, _In_ BOOLEAN FixHive)
Validates each value in the list by count. A value that is damaged gets removed from the list....
Definition: cmcheck.c:281
#define CM_CHECK_REGISTRY_VALUE_LIST_UNALLOCATED
Definition: cmlib.h:259
#define CM_CHECK_REGISTRY_VALUE_LIST_DATA_NOT_FOUND
Definition: cmlib.h:260
#define CM_CHECK_REGISTRY_VALUE_LIST_SIZE_NOT_SANE
Definition: cmlib.h:261

Referenced by CmpValidateKey().

◆ CmpValidateValueListByCount()

static CM_CHECK_REGISTRY_STATUS CmpValidateValueListByCount ( _In_ PHHIVE  Hive,
_In_ HCELL_INDEX  CurrentCell,
_In_ ULONG  ListCount,
_In_ PCELL_DATA  ValueListData,
_Out_ PULONG  ValuesRemoved,
_In_ BOOLEAN  FixHive 
)
static

Validates each value in the list by count. A value that is damaged gets removed from the list. This routine performs self-healing process in this case.

Parameters
[in]HiveA pointer to a hive descriptor of which a list of registry values is to be validated.
[in]CurrentCellThe current key cell that the value list points to.
[in]ListCountThe list count that describes the actual number of values in the list.
[in]ValueListDataA pointer to cell data of the current key cell that contains the value list to be validated.
[out]ValuesRemovedWhen the function finishes doing its operations, this parameter contains the amount of removed values from the list. A value of 0 indicates no values have been removed (which that would imply a self-healing process of the value list has occurred).
[in]FixHiveIf set to TRUE, the target hive will be fixed.
Returns
Returns CM_CHECK_REGISTRY_GOOD if the value list is sane. CM_CHECK_REGISTRY_VALUE_CELL_NIL is returned if a certain value cell is HCELL_NIL at specific count index. CM_CHECK_REGISTRY_VALUE_CELL_UNALLOCATED is returned if a certain value cell is unallocated at specific count index. CM_CHECK_REGISTRY_VALUE_CELL_DATA_NOT_FOUND is returned if cell data could not be mapped from the value cell, the value list is totally torn apart in this case. CM_CHECK_REGISTRY_VALUE_CELL_SIZE_NOT_SANE is returned if the value's size is bogus. CM_CHECK_REGISTRY_CORRUPT_VALUE_DATA is returned if the data inside the value is HCELL_NIL. CM_CHECK_REGISTRY_DATA_CELL_NOT_ALLOCATED is returned if the data cell inside the value is not allocated. CM_CHECK_REGISTRY_BAD_KEY_VALUE_SIGNATURE is returned if the value's signature is not valid.

Definition at line 281 of file cmcheck.c.

288{
289 ULONG ValueDataSize;
290 ULONG ListCountIndex;
292 HCELL_INDEX DataCell;
293 HCELL_INDEX ValueCell;
295 ULONG ValueNameLength, TotalValueNameLength;
296
297 PAGED_CODE();
298
299 ASSERT(ValueListData);
300 ASSERT(ListCount != 0);
301
302 /* Assume we haven't removed any value counts for now */
303 *ValuesRemoved = 0;
304
305 /*
306 * Begin looping each value in the list and
307 * validate it accordingly.
308 */
309 ListCountIndex = 0;
310 while (ListCountIndex < ListCount)
311 {
312 ValueCell = ValueListData->u.KeyList[ListCountIndex];
313 if (ValueCell == HCELL_NIL)
314 {
315 if (!CmpRepairValueListCount(Hive,
316 CurrentCell,
317 ListCountIndex,
318 ValueListData,
319 FixHive))
320 {
321 DPRINT1("The value cell is NIL (at index %u, list count %u)\n",
322 ListCountIndex, ListCount);
324 }
325
326 /* Decrease the list count and go to the next value */
327 ListCount--;
328 *ValuesRemoved++;
329 DPRINT1("Damaged value removed, continuing with the next value...\n");
330 continue;
331 }
332
333 if (!HvIsCellAllocated(Hive, ValueCell))
334 {
335 if (!CmpRepairValueListCount(Hive,
336 CurrentCell,
337 ListCountIndex,
338 ValueListData,
339 FixHive))
340 {
341 DPRINT1("The value cell is not allocated (at index %u, list count %u)\n",
342 ListCountIndex, ListCount);
344 }
345
346 /* Decrease the list count and go to the next value */
347 ListCount--;
348 *ValuesRemoved++;
349 DPRINT1("Damaged value removed, continuing with the next value...\n");
350 continue;
351 }
352
353 /* Obtain a cell data from this value */
354 ValueData = (PCELL_DATA)HvGetCell(Hive, ValueCell);
355 if (!ValueData)
356 {
357 DPRINT1("Cell data of the value cell not found (at index %u, value count %u)\n",
358 ListCountIndex, ListCount);
360 }
361
362 /* Check that the value size is sane */
363 ValueDataSize = HvGetCellSize(Hive, ValueData);
364 ValueNameLength = ValueData->u.KeyValue.NameLength;
365 TotalValueNameLength = ValueNameLength + FIELD_OFFSET(CM_KEY_VALUE, Name);
366 if (TotalValueNameLength > ValueDataSize)
367 {
368 if (!CmpRepairValueListCount(Hive,
369 CurrentCell,
370 ListCountIndex,
371 ValueListData,
372 FixHive))
373 {
374 DPRINT1("The total size is bigger than the actual cell size (total size %u, cell size %u, at index %u)\n",
375 TotalValueNameLength, ValueDataSize, ListCountIndex);
377 }
378
379 /* Decrease the list count and go to the next value */
380 ListCount--;
381 *ValuesRemoved++;
382 DPRINT1("Damaged value removed, continuing with the next value...\n");
383 continue;
384 }
385
386 /*
387 * The value cell has a sane size. The last thing
388 * to validate is the actual data of the value cell.
389 * That is, we want that the data itself and length
390 * are consistent. Technically speaking, value keys
391 * that are small are directly located in the value
392 * cell and it's built-in, in other words, the data
393 * is immediately present in the cell so we don't have
394 * to bother validating them since they're alright on
395 * their own. This can't be said the same about normal
396 * values though.
397 */
398 DataCell = ValueData->u.KeyValue.Data;
399 if (!CmpIsKeyValueSmall(&DataSize, ValueData->u.KeyValue.DataLength))
400 {
401 /* Validate the actual data based on size */
402 if (DataSize == 0)
403 {
404 if (DataCell != HCELL_NIL)
405 {
406 if (!CmpRepairValueListCount(Hive,
407 CurrentCell,
408 ListCountIndex,
409 ValueListData,
410 FixHive))
411 {
412 DPRINT1("The data is not NIL on a 0 length, data is corrupt\n");
414 }
415
416 /* Decrease the list count and go to the next value */
417 ListCount--;
418 *ValuesRemoved++;
419 DPRINT1("Damaged value removed, continuing with the next value...\n");
420 continue;
421 }
422 }
423 else
424 {
425 if (!HvIsCellAllocated(Hive, DataCell))
426 {
427 if (!CmpRepairValueListCount(Hive,
428 CurrentCell,
429 ListCountIndex,
430 ValueListData,
431 FixHive))
432 {
433 DPRINT1("The data is not NIL on a 0 length, data is corrupt\n");
435 }
436
437 /* Decrease the list count and go to the next value */
438 ListCount--;
439 *ValuesRemoved++;
440 DPRINT1("Damaged value removed, continuing with the next value...\n");
441 continue;
442 }
443 }
444
445 /* FIXME: Big values not supported yet */
447 }
448
449 /* Is the signature valid? */
450 if (ValueData->u.KeyValue.Signature != CM_KEY_VALUE_SIGNATURE)
451 {
452 if (!CmpRepairValueListCount(Hive,
453 CurrentCell,
454 ListCountIndex,
455 ValueListData,
456 FixHive))
457 {
458 DPRINT1("The key value signature is invalid\n");
460 }
461
462 /* Decrease the list count and go to the next value */
463 ListCount--;
464 *ValuesRemoved++;
465 DPRINT1("Damaged value removed, continuing with the next value...\n");
466 continue;
467 }
468
469 /* Advance to the next value */
470 ListCountIndex++;
471 }
472
474}
#define CM_KEY_VALUE_SIGNATURE
Definition: cmdata.h:24
BOOLEAN CMAPI CmpRepairValueListCount(_Inout_ PHHIVE Hive, _In_ HCELL_INDEX CurrentCell, _In_ ULONG ListCountIndex, _Inout_ PCELL_DATA ValueListData, _In_ BOOLEAN FixHive)
Repairs the value list count of key due to corruption. The process involves by removing one damaged v...
Definition: cmheal.c:697
#define CM_CHECK_REGISTRY_VALUE_CELL_DATA_NOT_FOUND
Definition: cmlib.h:264
#define CM_CHECK_REGISTRY_VALUE_CELL_UNALLOCATED
Definition: cmlib.h:263
#define CM_CHECK_REGISTRY_VALUE_CELL_SIZE_NOT_SANE
Definition: cmlib.h:265
#define ASSERT_VALUE_BIG(h, s)
Definition: cmlib.h:386
static BOOLEAN CmpIsKeyValueSmall(OUT PULONG RealLength, IN ULONG Length)
Definition: cmlib.h:395
#define CM_CHECK_REGISTRY_DATA_CELL_NOT_ALLOCATED
Definition: cmlib.h:267
#define CM_CHECK_REGISTRY_VALUE_CELL_NIL
Definition: cmlib.h:262
#define CM_CHECK_REGISTRY_CORRUPT_VALUE_DATA
Definition: cmlib.h:266
#define CM_CHECK_REGISTRY_BAD_KEY_VALUE_SIGNATURE
Definition: cmlib.h:268
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755

Referenced by CmpValidateValueList().

◆ HvValidateBin()

CM_CHECK_REGISTRY_STATUS NTAPI HvValidateBin ( _In_ PHHIVE  Hive,
_In_ PHBIN  Bin 
)

Validates a bin from a hive. It performs checks against the cells from this bin, ensuring the bin is not corrupt and that the cells are consistent with each other.

Parameters
[in]HiveA pointer to a hive descriptor of which a hive bin is to be validated.
[in]BinA pointer to a bin where its cells are to be validated.
Returns
CM_CHECK_REGISTRY_GOOD is returned if the bin is valid and not corrupt. CM_CHECK_REGISTRY_BIN_SIGNATURE_HEADER_CORRUPT is returned if this bin has a corrupt signature. CM_CHECK_REGISTRY_BAD_FREE_CELL is returned if the free cell has a bogus size. CM_CHECK_REGISTRY_BAD_ALLOC_CELL is returned for the allocated cell has a bogus size.

Definition at line 1414 of file cmcheck.c.

1417{
1418 PHCELL Cell, Basket;
1419
1420 PAGED_CODE();
1421
1422 ASSERT(Bin);
1423 ASSERT(Hive);
1424
1425 /* Ensure that this bin we got has valid signature header */
1426 if (Bin->Signature != HV_HBIN_SIGNATURE)
1427 {
1428 DPRINT1("The bin's signature header is corrupt\n");
1430 }
1431
1432 /*
1433 * Walk over all the cells from this bin and
1434 * validate that they're consistent with the bin.
1435 * Namely we want that each cell from this bin doesn't
1436 * have a bogus size.
1437 */
1438 Basket = (PHCELL)((PUCHAR)Bin + Bin->Size);
1439 for (Cell = GET_CELL_BIN(Bin);
1440 Cell < Basket;
1441 Cell = (PHCELL)((PUCHAR)Cell + abs(Cell->Size)))
1442 {
1443 if (IsFreeCell(Cell))
1444 {
1445 /*
1446 * This cell is free, check that
1447 * the size of this cell is not bogus.
1448 */
1449 if (Cell->Size > Bin->Size ||
1450 Cell->Size == 0)
1451 {
1452 /*
1453 * This cell has too much free space that
1454 * exceeds the boundary of the bin size.
1455 * Otherwise the cell doesn't have actual
1456 * free space (aka Size == 0) which is a
1457 * no go for a bin.
1458 */
1459 DPRINT1("The free cell exceeds the bin size or cell size equal to 0 (cell 0x%p, cell size %d, bin size %u)\n",
1460 Cell, Cell->Size, Bin->Size);
1462 }
1463 }
1464 else
1465 {
1466 /*
1467 * This cell is allocated, make sure that
1468 * the size of this cell is not bogus.
1469 */
1470 if (abs(Cell->Size) > Bin->Size)
1471 {
1472 /*
1473 * This cell allocated too much space
1474 * that exceeds the boundary of the
1475 * bin size.
1476 */
1477 DPRINT1("The allocated cell exceeds the bin size (cell 0x%p, cell size %d, bin size %u)\n",
1478 Cell, abs(Cell->Size), Bin->Size);
1480 }
1481 }
1482 }
1483
1485}
Definition: bin.h:44
#define GET_CELL_BIN(Bin)
Definition: cmcheck.c:27
#define CM_CHECK_REGISTRY_BAD_FREE_CELL
Definition: cmlib.h:243
#define CM_CHECK_REGISTRY_BAD_ALLOC_CELL
Definition: cmlib.h:244
#define CM_CHECK_REGISTRY_BIN_SIGNATURE_HEADER_CORRUPT
Definition: cmlib.h:242
#define abs(i)
Definition: fconv.c:206
#define HV_HBIN_SIGNATURE
Definition: hivedata.h:64
struct _HCELL * PHCELL
#define IsFreeCell(Cell)
Definition: hivedata.h:360
LONG Size
Definition: hivedata.h:215
unsigned char * PUCHAR
Definition: typedefs.h:53

Referenced by HvValidateHive().

◆ HvValidateHive()

CM_CHECK_REGISTRY_STATUS NTAPI HvValidateHive ( _In_ PHHIVE  Hive)

Validates a registry hive. This function ensures that the storage of this hive has valid bins.

Parameters
[in]HiveA pointer to a hive descriptor where validation on its hive bins is to be performed.
Returns
CM_CHECK_REGISTRY_GOOD is returned if the hive is valid. CM_CHECK_REGISTRY_HIVE_CORRUPT_SIGNATURE is returned if the hive has a corrupted signature. CM_CHECK_REGISTRY_BIN_SIZE_OR_OFFSET_CORRUPT is returned if the captured bin has a bad size. A failure CM status code is returned otherwise.

Definition at line 1506 of file cmcheck.c.

1508{
1509 CM_CHECK_REGISTRY_STATUS CmStatusCode;
1510 ULONG StorageIndex;
1511 ULONG BlockIndex;
1512 ULONG StorageLength;
1513 PHBIN Bin;
1514
1515 PAGED_CODE();
1516
1517 ASSERT(Hive);
1518
1519 /* Is the hive signature valid? */
1520 if (Hive->Signature != HV_HHIVE_SIGNATURE)
1521 {
1522 DPRINT1("Hive's signature corrupted (signature %u)\n", Hive->Signature);
1524 }
1525
1526 /*
1527 * Now loop each bin in the storage of this
1528 * hive.
1529 */
1530 for (StorageIndex = 0; StorageIndex < Hive->StorageTypeCount; StorageIndex++)
1531 {
1532 /* Get the storage length at this index */
1533 StorageLength = Hive->Storage[StorageIndex].Length;
1534
1535 for (BlockIndex = 0; BlockIndex < StorageLength;)
1536 {
1537 /* Go to the next if this bin does not exist */
1538 if (Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress == (ULONG_PTR)NULL)
1539 {
1540 continue;
1541 }
1542
1543 /*
1544 * Capture this bin and ensure that such
1545 * bin is within the offset and the size
1546 * is not bogus.
1547 */
1548 Bin = GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex);
1549 if (Bin->Size > (StorageLength * HBLOCK_SIZE) ||
1550 (Bin->FileOffset / HBLOCK_SIZE) != BlockIndex)
1551 {
1552 DPRINT1("Bin size or offset is corrupt (bin size %u, file offset %u, storage length %u)\n",
1553 Bin->Size, Bin->FileOffset, StorageLength);
1555 }
1556
1557 /* Validate the rest of the bin */
1558 CmStatusCode = HvValidateBin(Hive, Bin);
1559 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1560 {
1561 DPRINT1("This bin is not valid (bin 0x%p)\n", Bin);
1562 return CmStatusCode;
1563 }
1564
1565 /* Go to the next block */
1566 BlockIndex += Bin->Size / HBLOCK_SIZE;
1567 }
1568 }
1569
1571}
CM_CHECK_REGISTRY_STATUS NTAPI HvValidateBin(_In_ PHHIVE Hive, _In_ PHBIN Bin)
Validates a bin from a hive. It performs checks against the cells from this bin, ensuring the bin is ...
Definition: cmcheck.c:1414
#define GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex)
Definition: cmcheck.c:26
#define CM_CHECK_REGISTRY_HIVE_CORRUPT_SIGNATURE
Definition: cmlib.h:240
#define CM_CHECK_REGISTRY_BIN_SIZE_OR_OFFSET_CORRUPT
Definition: cmlib.h:241
#define HV_HHIVE_SIGNATURE
Definition: hivedata.h:62
#define HBLOCK_SIZE
Definition: hivedata.h:42
uint32_t ULONG_PTR
Definition: typedefs.h:65

Referenced by CmCheckRegistry().

Variable Documentation

◆ CmiVolatileHive