https://git.reactos.org/?p=reactos.git;a=commitdiff;h=54c552392f62f7369c6d7e...
commit 54c552392f62f7369c6d7e8395a671fe593afda1 Author: George Bișoc george.bisoc@reactos.org AuthorDate: Wed Oct 26 19:21:49 2022 +0200 Commit: George Bișoc george.bisoc@reactos.org CommitDate: Sun Nov 19 20:44:27 2023 +0100
[SDK][CMLIB] Implement self-heal registry helpers
This implements cmheal.c file which provides the basic registry self-heal infrastructure needed by the public CmCheckRegistry function. The infrastructure provides a range of various self-heal helpers for the hive, such as subkey, class, values and node healing functions. --- sdk/lib/cmlib/CMakeLists.txt | 1 + sdk/lib/cmlib/cmheal.c | 912 +++++++++++++++++++++++++++++++++++++++++++ sdk/lib/cmlib/cmlib.h | 73 ++++ 3 files changed, 986 insertions(+)
diff --git a/sdk/lib/cmlib/CMakeLists.txt b/sdk/lib/cmlib/CMakeLists.txt index 2ed0bc304b1..91ccbe6c3e5 100644 --- a/sdk/lib/cmlib/CMakeLists.txt +++ b/sdk/lib/cmlib/CMakeLists.txt @@ -5,6 +5,7 @@ add_definitions(
list(APPEND SOURCE cminit.c + cmheal.c cmindex.c cmkeydel.c cmname.c diff --git a/sdk/lib/cmlib/cmheal.c b/sdk/lib/cmlib/cmheal.c new file mode 100644 index 00000000000..9489d621bed --- /dev/null +++ b/sdk/lib/cmlib/cmheal.c @@ -0,0 +1,912 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Configuration Manager Library - Registry Self-Heal Routines + * COPYRIGHT: Copyright 2022 George Bișoc george.bisoc@reactos.org + */ + +#include "cmlib.h" +#define NDEBUG +#include <debug.h> + +/* GLOBALS ********************************************************************/ + +#if !defined(CMLIB_HOST) && !defined(_BLDR_) +extern BOOLEAN CmpSelfHeal; +extern ULONG CmpBootType; +#endif + +/* PRIVATE FUNCTIONS **********************************************************/ + +/** + * @brief + * Removes a cell from a fast key index. + * + * @param[in,out] FastIndex + * The fast key index where a cell has to be removed. + * + * @param[in] Index + * The index which points to the location of the + * cell that is to be removed. + * + * @param[in] UpdateCount + * If set to TRUE, the function will update the fast + * index count accordingly by one value less. If set + * to FALSE, the count won't be updated. See Remarks + * for further information. + * + * @remarks + * In case where the fast index count is not updated is + * when the key index is not a root but a leaf. In such + * scenario such leaf is the actual key index itself + * so updating the fast index count is not necessary (aka + * UpdateCount is set to FALSE). + */ +static +VOID +CmpRemoveFastIndexKeyCell( + _Inout_ PCM_KEY_FAST_INDEX FastIndex, + _In_ ULONG Index, + _In_ BOOLEAN UpdateCount) +{ + ULONG MoveCount; + ASSERT(Index < FastIndex->Count); + + /* Calculate the number of trailing cells */ + MoveCount = FastIndex->Count - Index - 1; + if (MoveCount != 0) + { + /* Remove the cell now by moving one location ahead */ + RtlMoveMemory(&FastIndex->List[Index], + &FastIndex->List[Index + 1], + MoveCount * sizeof(CM_INDEX)); + } + + /* Update the fast index count if asked */ + if (UpdateCount) + FastIndex->Count--; +} + +/** + * @brief + * Removes a cell from a normal key index. + * + * @param[in,out] KeyIndex + * The key index where a cell has to be removed. + * + * @param[in] Index + * The index which points to the location of the + * cell that is to be removed. + */ +static +VOID +CmpRemoveIndexKeyCell( + _Inout_ PCM_KEY_INDEX KeyIndex, + _In_ ULONG Index) +{ + ULONG MoveCount; + ASSERT(Index < KeyIndex->Count); + + /* Calculate the number of trailing cells */ + MoveCount = KeyIndex->Count - Index - 1; + if (MoveCount != 0) + { + /* Remove the cell now by moving one location ahead */ + RtlMoveMemory(&KeyIndex->List[Index], + &KeyIndex->List[Index + 1], + MoveCount * sizeof(HCELL_INDEX)); + } + + /* Update the key index count */ + KeyIndex->Count--; +} + +/** + * @brief + * Removes a cell from a key value list node. + * + * @param[in,out] ValueListNode + * The value list node which is used by the + * function to update the value list count. + * + * @param[in,out] ValueListData + * The value list data of which a cell has to be removed. + * + * @param[in] Index + * The index which points to the location of the + * cell that is to be removed. + */ +static +VOID +CmpRemoveValueFromValueList( + _Inout_ PCM_KEY_NODE ValueListNode, + _Inout_ PCELL_DATA ValueListData, + _In_ ULONG Index) +{ + ULONG MoveCount; + ASSERT(Index < ValueListNode->ValueList.Count); + + /* Calculate the number of trailing values */ + MoveCount = ValueListNode->ValueList.Count - Index - 1; + if (MoveCount != 0) + { + /* Remove the value now by moving one location ahead */ + RtlMoveMemory(&ValueListData->u.KeyList[Index], + &ValueListData->u.KeyList[Index + 1], + MoveCount * sizeof(HCELL_INDEX)); + } + + /* Update the value list count */ + ValueListNode->ValueList.Count--; +} + +/** + * @brief + * Removes the offending subkey from a root index. + * + * @param[in] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] RootIndex + * The root index where a leaf is obtained from. Such + * leaf is used to check deep down the leaf for the offending + * subkey. + * + * @param[in] TargetKey + * The offending target subkey to be removed. + * + * @return + * Returns TRUE if the function successfully removed the target + * key, FALSE otherwise. + */ +static +BOOLEAN +CmpRemoveSubkeyInRoot( + _In_ PHHIVE Hive, + _In_ PCM_KEY_INDEX RootIndex, + _In_ HCELL_INDEX TargetKey) +{ + PCM_KEY_INDEX Leaf; + PCM_KEY_FAST_INDEX FastIndex; + HCELL_INDEX LeafCell; + ULONG RootCountIndex; + ULONG LeafCountIndex; + + PAGED_CODE(); + + ASSERT(RootIndex); + + /* Loop the root index */ + for (RootCountIndex = 0; RootCountIndex < RootIndex->Count; RootCountIndex++) + { + /* + * Release the leaf cell from previous iteration + * of the loop. Make sure what we're releasing is + * valid to begin with. + */ + if (RootCountIndex) + { + ASSERT(Leaf); + ASSERT(LeafCell == RootIndex->List[RootCountIndex - 1]); + HvReleaseCell(Hive, LeafCell); + } + + /* Get the leaf cell and the leaf for this index */ + LeafCell = RootIndex->List[RootCountIndex]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) + { + DPRINT1("Couldn't get the leaf from cell\n"); + return FALSE; + } + + /* Start looping the leaf */ + for (LeafCountIndex = 0; LeafCountIndex < Leaf->Count; LeafCountIndex++) + { + /* Is the leaf a fast leaf or a hash one? */ + if ((Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)) + { + /* It is one of the two, get the fast index */ + FastIndex = (PCM_KEY_FAST_INDEX)Leaf; + + /* + * Is the subkey cell from the fast + * index the one we one we're actually + * searching? + */ + if (FastIndex->List[LeafCountIndex].Cell == TargetKey) + { + HvReleaseCell(Hive, LeafCell); + HvMarkCellDirty(Hive, LeafCell, FALSE); + CmpRemoveFastIndexKeyCell(FastIndex, LeafCountIndex, TRUE); + DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, index %lu)\n", + FastIndex, LeafCountIndex); + return TRUE; + } + } + else + { + /* + * The leaf is neither of the two. Check if + * the target offending cell is inside the leaf + * itself. + */ + if (Leaf->List[LeafCountIndex] == TargetKey) + { + HvReleaseCell(Hive, LeafCell); + HvMarkCellDirty(Hive, LeafCell, FALSE); + CmpRemoveIndexKeyCell(Leaf, LeafCountIndex); + DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n", + Leaf, LeafCountIndex); + return TRUE; + } + } + } + } + + /* + * We have searched everywhere but we couldn't + * hunt the offending target key cell. + */ + DPRINT1("No target key has been found to remove\n"); + return FALSE; +} + +/** + * @brief + * Removes the offending subkey from a leaf index. + * + * @param[in] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] KeyNode + * A pointer to a key node of the parent. This node is + * used by the function to mark the whole subkeys list + * of the parent dirty. + * + * @param[in] Leaf + * A pointer to a leaf key index of which the offending + * subkey is to be removed from. + * + * @param[in] TargetKey + * The offending target subkey to remove. + * + * @return + * Returns TRUE if the function successfully removed the target + * key, FALSE otherwise. + */ +static +BOOLEAN +CmpRemoveSubKeyInLeaf( + _In_ PHHIVE Hive, + _In_ PCM_KEY_NODE KeyNode, + _In_ PCM_KEY_INDEX Leaf, + _In_ HCELL_INDEX TargetKey) +{ + PCM_KEY_FAST_INDEX FastIndex; + ULONG LeafIndex; + + /* Loop the leaf index */ + for (LeafIndex = 0; LeafIndex < Leaf->Count; LeafIndex++) + { + /* + * Check if the main leaf is a fast + * leaf or a hash one. + */ + if ((Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)) + { + /* It is one of the two, get the fast index */ + FastIndex = (PCM_KEY_FAST_INDEX)Leaf; + + /* + * Is the subkey cell from the fast + * index the one we're actually + * searching? + */ + if (FastIndex->List[LeafIndex].Cell == TargetKey) + { + HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE); + CmpRemoveFastIndexKeyCell(FastIndex, LeafIndex, FALSE); + + /* + * Since this fast index actually came from the + * actual leaf index itself, just update its count + * rather than that of the fast index. + */ + Leaf->Count--; + DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, leaf index %lu)\n", + FastIndex, LeafIndex); + return TRUE; + } + } + else + { + /* + * The leaf is neither of the two. The offending + * cell must come directly from the normal leaf + * at this point. + */ + if (Leaf->List[LeafIndex] == TargetKey) + { + HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE); + CmpRemoveIndexKeyCell(Leaf, LeafIndex); + DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n", + Leaf, LeafIndex); + return TRUE; + } + } + } + + /* + * We have searched everywhere but we couldn't + * hunt the offending target key cell. + */ + DPRINT1("No target key has been found to remove\n"); + return FALSE; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/** + * @brief + * Checks if self healing is permitted by the kernel and/or + * bootloader. Self healing is also triggered if such a + * request was prompted by the user to fix a broken hive. + * Such a request tipically comes from a registry repair + * tool such as the ReactOS Check Registry Utility. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if self healing is possible, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmIsSelfHealEnabled( + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + if (FixHive) + return TRUE; + +#if !defined(CMLIB_HOST) && !defined(_BLDR_) + if (CmpSelfHeal || (CmpBootType & HBOOT_TYPE_SELF_HEAL)) + return TRUE; +#endif + + return FALSE; +} + +/** + * @brief + * Repairs the parent key from damage by removing the + * offending subkey cell. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] TargetKey + * The offending target cell to remove from the parent. + * + * @param[in] ParentKey + * The damaged parent key cell to heal. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the parent + * key, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairParentKey( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX TargetKey, + _In_ HCELL_INDEX ParentKey, + _In_ BOOLEAN FixHive) +{ + PCM_KEY_INDEX KeyIndex; + PCM_KEY_NODE KeyNode; + BOOLEAN ParentRepaired; + + PAGED_CODE(); + + /* The target key must NEVER be NIL! */ + ASSERT(TargetKey != HCELL_NIL); + + /* Assume the parent hasn't been repaired yet */ + ParentRepaired = FALSE; + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return ParentRepaired; + } + + /* Obtain a node from the parent */ + KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); + if (!KeyNode) + { + DPRINT1("Couldn't get the parent key node\n"); + return ParentRepaired; + } + + /* Obtain the index as well since we got the parent node */ + KeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Stable]); + if (!KeyIndex) + { + DPRINT1("Couldn't get the key index from parent node\n"); + HvReleaseCell(Hive, ParentKey); + return ParentRepaired; + } + + /* Check if this is a root */ + if (KeyIndex->Signature == CM_KEY_INDEX_ROOT) + { + /* It is, call the specific helper to discard the damaged key down the root */ + ParentRepaired = CmpRemoveSubkeyInRoot(Hive, + KeyIndex, + TargetKey); + } + else if ((KeyIndex->Signature == CM_KEY_INDEX_LEAF) || + (KeyIndex->Signature == CM_KEY_FAST_LEAF) || + (KeyIndex->Signature == CM_KEY_HASH_LEAF)) + { + /* Otherwise call the leaf helper */ + ParentRepaired = CmpRemoveSubKeyInLeaf(Hive, + KeyNode, + KeyIndex, + TargetKey); + } + else + { + /* + * Generally CmCheckRegistry detects if a key index + * in the subkeys list is totally broken (we understand + * that if its signature is not root or leaf) and it will + * purge the whole subkeys list in such cases. With that + * being said, we should never reach this code path. But + * if for whatever reason we reach here then something + * is seriously wrong. + */ + DPRINT1("The key index signature is invalid (KeyIndex->Signature == %lu)", KeyIndex->Signature); + ASSERT(FALSE); + } + + /* + * If we successfully removed the offending key + * cell mark down the parent as dirty and punt down + * the subkey count as well. Mark the hive as in + * self heal mode as well. + */ + if (ParentRepaired) + { + HvMarkCellDirty(Hive, ParentKey, FALSE); + KeyNode->SubKeyCounts[Stable]--; + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + DPRINT1("The subkey has been removed, the parent is now repaired\n"); + } + + HvReleaseCell(Hive, KeyNode->SubKeyLists[Stable]); + HvReleaseCell(Hive, ParentKey); + return ParentRepaired; +} + +/** + * @brief + * Repairs the parent of the node from damage due + * to parent cell and parent node incosistency. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in] ParentCell + * The sane parent cell which is used by the + * function for new parent node assignment. + * + * @param[in,out] CellData + * The cell data of the current cell of which + * its parent node is to be repaired. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * parent node, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairParentNode( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ HCELL_INDEX ParentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Mark the cell where we got the actual + * cell data as dirty and fix the node. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + CellData->u.KeyNode.Parent = ParentCell; + + /* Mark the hive as in self healing mode since we repaired it */ + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + return TRUE; +} + +/** + * @brief + * Repairs the key node signature from damage + * due to signature corruption. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in,out] CellData + * The cell data of the current cell of which + * its signature is to be repaired. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * key node signature, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairKeyNodeSignature( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Mark the cell where we got the actual + * cell data as dirty and fix the key signature. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE; + + /* Mark the hive as in self healing mode since we repaired it */ + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + return TRUE; +} + +/** + * @brief + * Repairs the class from damage due to class + * corruption within the node key. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in,out] CellData + * The cell data of the current cell of which + * its class is to be repaired. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * class of node key, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairClassOfNodeKey( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Mark the cell where we got the actual + * cell data as dirty and fix the class field + * of key node. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + CellData->u.KeyNode.Class = HCELL_NIL; + CellData->u.KeyNode.ClassLength = 0; + + /* Mark the hive as in self healing mode since we repaired it */ + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + return TRUE; +} + +/** + * @brief + * Repairs the value list count of key due to + * corruption. The process involves by removing + * one damaged value less from the list. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in] ListCountIndex + * The value count index which points to the actual + * value in the list to be removed. + * + * @param[in,out] ValueListData + * The value list cell data containing the actual list + * of which the damaged is to be removed from. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * value list count, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairValueListCount( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ ULONG ListCountIndex, + _Inout_ PCELL_DATA ValueListData, + _In_ BOOLEAN FixHive) +{ + PCM_KEY_NODE ValueListNode; + + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Obtain a node from the cell that we mark it as dirty. + * The node is that of the current cell of which its + * value list is being validated. + */ + ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); + if (!ValueListNode) + { + DPRINT1("Could not get a node from the current cell\n"); + return FALSE; + } + + /* + * Mark the current cell and value list as dirty + * as we will be making changes onto them. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + HvMarkCellDirty(Hive, ValueListNode->ValueList.List, FALSE); + + /* + * Now remove the value from the list and mark the + * hive as in self healing mode. + */ + CmpRemoveValueFromValueList(ValueListNode, ValueListData, ListCountIndex); + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + HvReleaseCell(Hive, CurrentCell); + return TRUE; +} + +/** + * @brief + * Repairs the value list due to corruption. The + * process involes by purging the whole damaged + * list. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * value list, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairValueList( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ BOOLEAN FixHive) +{ + PCM_KEY_NODE ValueListNode; + + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* Obtain a node */ + ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); + if (!ValueListNode) + { + DPRINT1("Could not get a node from the current cell\n"); + return FALSE; + } + + /* Purge out the whole list */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + ValueListNode->ValueList.List = HCELL_NIL; + ValueListNode->ValueList.Count = 0; + + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + HvReleaseCell(Hive, CurrentCell); + return TRUE; +} + +/** + * @brief + * Repairs the subkey list count due to corruption. + * The process involves by fixing the count itself + * with a sane count. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in] Count + * The healthy count which is used by the function + * to fix the subkeys list count. + * + * @param[in,out] CellData + * The cell data of the current cell of which its + * subkeys list is to be fixed. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * subkeys list count, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairSubKeyCounts( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ ULONG Count, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Mark the cell where we got the actual + * cell data as dirty and fix the subkey + * counts. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + CellData->u.KeyNode.SubKeyCounts[Stable] = Count; + + /* Mark the hive as in self healing mode since we repaired it */ + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + return TRUE; +} + +/** + * @brief + * Repairs the subkey list due to corruption. The process + * involves by purging the whole damaged subkeys list. + * + * @param[in,out] Hive + * A pointer to a hive descriptor containing faulty data. + * + * @param[in] CurrentCell + * The current cell to be marked as dirty. + * + * @param[in,out] CellData + * The cell data of the current cell of which its + * subkeys list is to be fixed. + * + * @param[in] FixHive + * If set to TRUE, self heal is triggered and the target + * hive will be fixed. Otherwise the hive will not be fixed. + * + * @return + * Returns TRUE if the function successfully healed the + * subkeys list, FALSE otherwise. + */ +BOOLEAN +CMAPI +CmpRepairSubKeyList( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive) +{ + PAGED_CODE(); + + /* Is self healing possible? */ + if (!CmIsSelfHealEnabled(FixHive)) + { + DPRINT1("Self healing not possible\n"); + return FALSE; + } + + /* + * Mark the cell where we got the actual + * cell data as dirty and fix the subkey + * list. + */ + HvMarkCellDirty(Hive, CurrentCell, FALSE); + CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL; + CellData->u.KeyNode.SubKeyCounts[Stable] = 0; + + /* Mark the hive as in self healing mode since we repaired it */ + Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; + return TRUE; +} + +/* EOF */ diff --git a/sdk/lib/cmlib/cmlib.h b/sdk/lib/cmlib/cmlib.h index 4f02daf32e5..65f66f581b0 100644 --- a/sdk/lib/cmlib/cmlib.h +++ b/sdk/lib/cmlib/cmlib.h @@ -482,6 +482,79 @@ ULONG CMAPI HvpHiveHeaderChecksum( PHBASE_BLOCK HiveHeader);
+// +// Registry Self-Heal Routines +// +BOOLEAN +CMAPI +CmIsSelfHealEnabled( + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairParentKey( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX TargetKey, + _In_ HCELL_INDEX ParentKey, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairParentNode( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX DirtyCell, + _In_ HCELL_INDEX ParentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairKeyNodeSignature( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX DirtyCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairClassOfNodeKey( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX DirtyCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairValueList( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairValueListCount( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ ULONG ListCountIndex, + _Inout_ PCELL_DATA ValueListData, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairSubKeyCounts( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _In_ ULONG Count, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive); + +BOOLEAN +CMAPI +CmpRepairSubKeyList( + _Inout_ PHHIVE Hive, + _In_ HCELL_INDEX CurrentCell, + _Inout_ PCELL_DATA CellData, + _In_ BOOLEAN FixHive);
/* Old-style Public "Cmlib" functions */