ReactOS 0.4.15-dev-7953-g1f49173
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 1633 of file cmcheck.c.

1636{
1637 CM_CHECK_REGISTRY_STATUS CmStatusCode;
1638 PHHIVE Hive;
1639 BOOLEAN ShouldFixHive = FALSE;
1640
1641 PAGED_CODE();
1642
1643 /* Bail out if the caller did not give a hive */
1644 if (!RegistryHive)
1645 {
1646 DPRINT1("No registry hive given for check\n");
1648 }
1649
1650#if !defined(CMLIB_HOST) && !defined(_BLDR_)
1651 /*
1652 * The master hive is the root of the registry,
1653 * it holds all other hives together. So do not
1654 * do any validation checks.
1655 */
1656 if (RegistryHive == CmiVolatileHive)
1657 {
1658 DPRINT("This is master registry hive, don't do anything\n");
1660 }
1661#endif
1662
1663 /* Bail out if no valid flag is given */
1669 {
1670 DPRINT1("Invalid flag for registry check given (flag %lu)\n", Flags);
1672 }
1673
1674 /*
1675 * Obtain the hive and check if the caller wants
1676 * that the hive to be validated.
1677 */
1678 Hive = GET_HHIVE(RegistryHive);
1680 {
1681 CmStatusCode = HvValidateHive(Hive);
1682 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1683 {
1684 DPRINT1("The hive is not valid (hive 0x%p, check status code %lu)\n", Hive, CmStatusCode);
1685 return CmStatusCode;
1686 }
1687 }
1688
1689 /*
1690 * A registry repair tool such as the ReactOS Check Registry
1691 * Utility wants the damaged hive to be fixed as we check the
1692 * target hive.
1693 */
1695 {
1696 ShouldFixHive = TRUE;
1697 }
1698
1699 /*
1700 * FIXME: Currently ReactOS does not implement security
1701 * caching algorithms so it's pretty pointless to implement
1702 * security descriptors validation checks at this moment.
1703 * When the time comes to implement these, we would need
1704 * to implement security checks here as well.
1705 */
1706
1707 /* Call the internal API to do the rest of the work bulk */
1708 CmStatusCode = CmpValidateRegistryInternal(Hive, Flags, FALSE, ShouldFixHive);
1709 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1710 {
1711 DPRINT1("The hive is not valid (hive 0x%p, check status code %lu)\n", Hive, CmStatusCode);
1712 return CmStatusCode;
1713 }
1714
1715 return CmStatusCode;
1716}
#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:1505
#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:1147
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:71
_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 %lu)\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 %lu, cell size %lu)\n", TotalKeyNameLength, CellSize);
1005 }
1006
1007 /* Is the parent cell consistent? */
1008 if (ParentCell != HCELL_NIL &&
1009 ParentCell != CellData->u.KeyNode.Parent)
1010 {
1011 if (!CmpRepairParentNode(Hive,
1012 CurrentCell,
1013 ParentCell,
1014 CellData,
1015 FixHive))
1016 {
1017 DPRINT1("The parent key node doesn't point to the actual parent\n");
1019 }
1020 }
1021
1022 /* Is the key node signature valid? */
1023 if (CellData->u.KeyNode.Signature != CM_KEY_NODE_SIGNATURE)
1024 {
1025 if (!CmpRepairKeyNodeSignature(Hive,
1026 CurrentCell,
1027 CellData,
1028 FixHive))
1029 {
1030 DPRINT1("The parent key node signature is not valid\n");
1032 }
1033 }
1034
1035 /*
1036 * FIXME: Security cell checks have to be implemented here
1037 * once we properly and reliably implement security caching
1038 * in the kernel.
1039 */
1040
1041 /* Validate the class */
1042 CmStatusCode = CmpValidateClass(Hive, CurrentCell, CellData);
1043 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1044 {
1045 if (!CmpRepairClassOfNodeKey(Hive,
1046 CurrentCell,
1047 CellData,
1048 FixHive))
1049 {
1050 DPRINT1("Failed to repair the hive, the cell class is not valid\n");
1051 return CmStatusCode;
1052 }
1053 }
1054
1055 /* Validate the value list */
1056 CmStatusCode = CmpValidateValueList(Hive, CurrentCell, CellData, FixHive);
1057 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1058 {
1059 /*
1060 * It happens that a certain value in the list
1061 * is so bad like we couldn't map a cell data from it
1062 * or the list itself is toast. In such cases what we
1063 * can do here is to do a "value list sacrifice", aka
1064 * purge the whole list.
1065 */
1066 if (!CmpRepairValueList(Hive, CurrentCell, FixHive))
1067 {
1068 DPRINT1("Failed to repair the hive, the value list is corrupt\n");
1069 return CmStatusCode;
1070 }
1071 }
1072
1073 /* Validate the subkeys list */
1074 CmStatusCode = CmpValidateSubKeyList(Hive, CurrentCell, CellData, FixHive, &DoSubkeysRepair);
1075 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1076 {
1077 /*
1078 * The subkeys list is in trouble. Worse when the actual
1079 * subkey list is so severed this key is also kaput on itself.
1080 */
1081 if (!DoSubkeysRepair)
1082 {
1083 DPRINT1("The subkeys list is totally corrupt, can't repair\n");
1084 return CmStatusCode;
1085 }
1086
1087 /*
1088 * OK, there's still some salvation for this key.
1089 * Purge the whole subkeys list in order to fix it.
1090 */
1091 if (!CmpRepairSubKeyList(Hive,
1092 CurrentCell,
1093 CellData,
1094 FixHive))
1095 {
1096 DPRINT1("Failed to repair the hive, the subkeys list is corrupt!\n");
1097 return CmStatusCode;
1098 }
1099 }
1100
1101 /* Purge volatile data if needed */
1102 CmpPurgeVolatiles(Hive, CurrentCell, CellData, Flags);
1104}
#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:765
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:637
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:532
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:585
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:883
#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:317
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
union _CELL_DATA::@4303 u
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 1147 of file cmcheck.c.

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

1416{
1417 PHCELL Cell, Basket;
1418
1419 PAGED_CODE();
1420
1421 ASSERT(Bin);
1422 ASSERT(Hive);
1423
1424 /* Ensure that this bin we got has valid signature header */
1425 if (Bin->Signature != HV_HBIN_SIGNATURE)
1426 {
1427 DPRINT1("The bin's signature header is corrupt\n");
1429 }
1430
1431 /*
1432 * Walk over all the cells from this bin and
1433 * validate that they're consistent with the bin.
1434 * Namely we want that each cell from this bin doesn't
1435 * have a bogus size.
1436 */
1437 Basket = (PHCELL)((PUCHAR)Bin + Bin->Size);
1438 for (Cell = GET_CELL_BIN(Bin);
1439 Cell < Basket;
1440 Cell = (PHCELL)((PUCHAR)Cell + abs(Cell->Size)))
1441 {
1442 if (IsFreeCell(Cell))
1443 {
1444 /*
1445 * This cell is free, check that
1446 * the size of this cell is not bogus.
1447 */
1448 if (Cell->Size > Bin->Size ||
1449 Cell->Size == 0)
1450 {
1451 /*
1452 * This cell has too much free space that
1453 * exceeds the boundary of the bin size.
1454 * Otherwise the cell doesn't have actual
1455 * free space (aka Size == 0) which is a
1456 * no go for a bin.
1457 */
1458 DPRINT1("The free cell exceeds the bin size or cell size equal to 0 (cell 0x%p, cell size %d, bin size %lu)\n",
1459 Cell, Cell->Size, Bin->Size);
1461 }
1462 }
1463 else
1464 {
1465 /*
1466 * This cell is allocated, make sure that
1467 * the size of this cell is not bogus.
1468 */
1469 if (abs(Cell->Size) > Bin->Size)
1470 {
1471 /*
1472 * This cell allocated too much space
1473 * that exceeds the boundary of the
1474 * bin size.
1475 */
1476 DPRINT1("The allocated cell exceeds the bin size (cell 0x%p, cell size %d, bin size %lu)\n",
1477 Cell, abs(Cell->Size), Bin->Size);
1479 }
1480 }
1481 }
1482
1484}
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 1505 of file cmcheck.c.

1507{
1508 CM_CHECK_REGISTRY_STATUS CmStatusCode;
1509 ULONG StorageIndex;
1510 ULONG BlockIndex;
1511 ULONG StorageLength;
1512 PHBIN Bin;
1513
1514 PAGED_CODE();
1515
1516 ASSERT(Hive);
1517
1518 /* Is the hive signature valid? */
1519 if (Hive->Signature != HV_HHIVE_SIGNATURE)
1520 {
1521 DPRINT1("Hive's signature corrupted (signature %lu)\n", Hive->Signature);
1523 }
1524
1525 /*
1526 * Now loop each bin in the storage of this
1527 * hive.
1528 */
1529 for (StorageIndex = 0; StorageIndex < Hive->StorageTypeCount; StorageIndex++)
1530 {
1531 /* Get the storage length at this index */
1532 StorageLength = Hive->Storage[StorageIndex].Length;
1533
1534 for (BlockIndex = 0; BlockIndex < StorageLength;)
1535 {
1536 /* Go to the next if this bin does not exist */
1537 if (Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress == (ULONG_PTR)NULL)
1538 {
1539 continue;
1540 }
1541
1542 /*
1543 * Capture this bin and ensure that such
1544 * bin is within the offset and the size
1545 * is not bogus.
1546 */
1547 Bin = GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex);
1548 if (Bin->Size > (StorageLength * HBLOCK_SIZE) ||
1549 (Bin->FileOffset / HBLOCK_SIZE) != BlockIndex)
1550 {
1551 DPRINT1("Bin size or offset is corrupt (bin size %lu, file offset %lu, storage length %lu)\n",
1552 Bin->Size, Bin->FileOffset, StorageLength);
1554 }
1555
1556 /* Validate the rest of the bin */
1557 CmStatusCode = HvValidateBin(Hive, Bin);
1558 if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode))
1559 {
1560 DPRINT1("This bin is not valid (bin 0x%p)\n", Bin);
1561 return CmStatusCode;
1562 }
1563
1564 /* Go to the next block */
1565 BlockIndex += Bin->Size / HBLOCK_SIZE;
1566 }
1567 }
1568
1570}
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:1413
#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