1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Configuration Manager Library - Registry Self-Heal Routines
5 * COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org>
6 */
7
8 #include "cmlib.h"
9 #define NDEBUG
10 #include <debug.h>
11
12 /* GLOBALS ********************************************************************/
13
14 #if !defined(CMLIB_HOST) && !defined(_BLDR_)
15 extern BOOLEAN CmpSelfHeal;
16 extern ULONG CmpBootType;
17 #endif
18
19 /* PRIVATE FUNCTIONS **********************************************************/
20
21 /**
22 * @brief
23 * Removes a cell from a fast key index.
24 *
25 * @param[in,out] FastIndex
26 * The fast key index where a cell has to be removed.
27 *
28 * @param[in] Index
29 * The index which points to the location of the
30 * cell that is to be removed.
31 *
32 * @param[in] UpdateCount
33 * If set to TRUE, the function will update the fast
34 * index count accordingly by one value less. If set
35 * to FALSE, the count won't be updated. See Remarks
36 * for further information.
37 *
38 * @remarks
39 * In case where the fast index count is not updated is
40 * when the key index is not a root but a leaf. In such
41 * scenario such leaf is the actual key index itself
42 * so updating the fast index count is not necessary (aka
43 * UpdateCount is set to FALSE).
44 */
45 static
46 VOID
CmpRemoveFastIndexKeyCell(_Inout_ PCM_KEY_FAST_INDEX FastIndex,_In_ ULONG Index,_In_ BOOLEAN UpdateCount)47 CmpRemoveFastIndexKeyCell(
48 _Inout_ PCM_KEY_FAST_INDEX FastIndex,
49 _In_ ULONG Index,
50 _In_ BOOLEAN UpdateCount)
51 {
52 ULONG MoveCount;
53 ASSERT(Index < FastIndex->Count);
54
55 /* Calculate the number of trailing cells */
56 MoveCount = FastIndex->Count - Index - 1;
57 if (MoveCount != 0)
58 {
59 /* Remove the cell now by moving one location ahead */
60 RtlMoveMemory(&FastIndex->List[Index],
61 &FastIndex->List[Index + 1],
62 MoveCount * sizeof(CM_INDEX));
63 }
64
65 /* Update the fast index count if asked */
66 if (UpdateCount)
67 FastIndex->Count--;
68 }
69
70 /**
71 * @brief
72 * Removes a cell from a normal key index.
73 *
74 * @param[in,out] KeyIndex
75 * The key index where a cell has to be removed.
76 *
77 * @param[in] Index
78 * The index which points to the location of the
79 * cell that is to be removed.
80 */
81 static
82 VOID
CmpRemoveIndexKeyCell(_Inout_ PCM_KEY_INDEX KeyIndex,_In_ ULONG Index)83 CmpRemoveIndexKeyCell(
84 _Inout_ PCM_KEY_INDEX KeyIndex,
85 _In_ ULONG Index)
86 {
87 ULONG MoveCount;
88 ASSERT(Index < KeyIndex->Count);
89
90 /* Calculate the number of trailing cells */
91 MoveCount = KeyIndex->Count - Index - 1;
92 if (MoveCount != 0)
93 {
94 /* Remove the cell now by moving one location ahead */
95 RtlMoveMemory(&KeyIndex->List[Index],
96 &KeyIndex->List[Index + 1],
97 MoveCount * sizeof(HCELL_INDEX));
98 }
99
100 /* Update the key index count */
101 KeyIndex->Count--;
102 }
103
104 /**
105 * @brief
106 * Removes a cell from a key value list node.
107 *
108 * @param[in,out] ValueListNode
109 * The value list node which is used by the
110 * function to update the value list count.
111 *
112 * @param[in,out] ValueListData
113 * The value list data of which a cell has to be removed.
114 *
115 * @param[in] Index
116 * The index which points to the location of the
117 * cell that is to be removed.
118 */
119 static
120 VOID
CmpRemoveValueFromValueList(_Inout_ PCM_KEY_NODE ValueListNode,_Inout_ PCELL_DATA ValueListData,_In_ ULONG Index)121 CmpRemoveValueFromValueList(
122 _Inout_ PCM_KEY_NODE ValueListNode,
123 _Inout_ PCELL_DATA ValueListData,
124 _In_ ULONG Index)
125 {
126 ULONG MoveCount;
127 ASSERT(Index < ValueListNode->ValueList.Count);
128
129 /* Calculate the number of trailing values */
130 MoveCount = ValueListNode->ValueList.Count - Index - 1;
131 if (MoveCount != 0)
132 {
133 /* Remove the value now by moving one location ahead */
134 RtlMoveMemory(&ValueListData->u.KeyList[Index],
135 &ValueListData->u.KeyList[Index + 1],
136 MoveCount * sizeof(HCELL_INDEX));
137 }
138
139 /* Update the value list count */
140 ValueListNode->ValueList.Count--;
141 }
142
143 /**
144 * @brief
145 * Removes the offending subkey from a root index.
146 *
147 * @param[in] Hive
148 * A pointer to a hive descriptor containing faulty data.
149 *
150 * @param[in] RootIndex
151 * The root index where a leaf is obtained from. Such
152 * leaf is used to check deep down the leaf for the offending
153 * subkey.
154 *
155 * @param[in] TargetKey
156 * The offending target subkey to be removed.
157 *
158 * @return
159 * Returns TRUE if the function successfully removed the target
160 * key, FALSE otherwise.
161 */
162 static
163 BOOLEAN
CmpRemoveSubkeyInRoot(_In_ PHHIVE Hive,_In_ PCM_KEY_INDEX RootIndex,_In_ HCELL_INDEX TargetKey)164 CmpRemoveSubkeyInRoot(
165 _In_ PHHIVE Hive,
166 _In_ PCM_KEY_INDEX RootIndex,
167 _In_ HCELL_INDEX TargetKey)
168 {
169 PCM_KEY_INDEX Leaf;
170 PCM_KEY_FAST_INDEX FastIndex;
171 HCELL_INDEX LeafCell;
172 ULONG RootCountIndex;
173 ULONG LeafCountIndex;
174
175 PAGED_CODE();
176
177 ASSERT(RootIndex);
178
179 /* Loop the root index */
180 for (RootCountIndex = 0; RootCountIndex < RootIndex->Count; RootCountIndex++)
181 {
182 /*
183 * Release the leaf cell from previous iteration
184 * of the loop. Make sure what we're releasing is
185 * valid to begin with.
186 */
187 if (RootCountIndex)
188 {
189 ASSERT(Leaf);
190 ASSERT(LeafCell == RootIndex->List[RootCountIndex - 1]);
191 HvReleaseCell(Hive, LeafCell);
192 }
193
194 /* Get the leaf cell and the leaf for this index */
195 LeafCell = RootIndex->List[RootCountIndex];
196 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
197 if (!Leaf)
198 {
199 DPRINT1("Couldn't get the leaf from cell\n");
200 return FALSE;
201 }
202
203 /* Start looping the leaf */
204 for (LeafCountIndex = 0; LeafCountIndex < Leaf->Count; LeafCountIndex++)
205 {
206 /* Is the leaf a fast leaf or a hash one? */
207 if ((Leaf->Signature == CM_KEY_FAST_LEAF) ||
208 (Leaf->Signature == CM_KEY_HASH_LEAF))
209 {
210 /* It is one of the two, get the fast index */
211 FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
212
213 /*
214 * Is the subkey cell from the fast
215 * index the one we one we're actually
216 * searching?
217 */
218 if (FastIndex->List[LeafCountIndex].Cell == TargetKey)
219 {
220 HvReleaseCell(Hive, LeafCell);
221 HvMarkCellDirty(Hive, LeafCell, FALSE);
222 CmpRemoveFastIndexKeyCell(FastIndex, LeafCountIndex, TRUE);
223 DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, index %u)\n",
224 FastIndex, LeafCountIndex);
225 return TRUE;
226 }
227 }
228 else
229 {
230 /*
231 * The leaf is neither of the two. Check if
232 * the target offending cell is inside the leaf
233 * itself.
234 */
235 if (Leaf->List[LeafCountIndex] == TargetKey)
236 {
237 HvReleaseCell(Hive, LeafCell);
238 HvMarkCellDirty(Hive, LeafCell, FALSE);
239 CmpRemoveIndexKeyCell(Leaf, LeafCountIndex);
240 DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %u)\n",
241 Leaf, LeafCountIndex);
242 return TRUE;
243 }
244 }
245 }
246 }
247
248 /*
249 * We have searched everywhere but we couldn't
250 * hunt the offending target key cell.
251 */
252 DPRINT1("No target key has been found to remove\n");
253 return FALSE;
254 }
255
256 /**
257 * @brief
258 * Removes the offending subkey from a leaf index.
259 *
260 * @param[in] Hive
261 * A pointer to a hive descriptor containing faulty data.
262 *
263 * @param[in] KeyNode
264 * A pointer to a key node of the parent. This node is
265 * used by the function to mark the whole subkeys list
266 * of the parent dirty.
267 *
268 * @param[in] Leaf
269 * A pointer to a leaf key index of which the offending
270 * subkey is to be removed from.
271 *
272 * @param[in] TargetKey
273 * The offending target subkey to remove.
274 *
275 * @return
276 * Returns TRUE if the function successfully removed the target
277 * key, FALSE otherwise.
278 */
279 static
280 BOOLEAN
CmpRemoveSubKeyInLeaf(_In_ PHHIVE Hive,_In_ PCM_KEY_NODE KeyNode,_In_ PCM_KEY_INDEX Leaf,_In_ HCELL_INDEX TargetKey)281 CmpRemoveSubKeyInLeaf(
282 _In_ PHHIVE Hive,
283 _In_ PCM_KEY_NODE KeyNode,
284 _In_ PCM_KEY_INDEX Leaf,
285 _In_ HCELL_INDEX TargetKey)
286 {
287 PCM_KEY_FAST_INDEX FastIndex;
288 ULONG LeafIndex;
289
290 /* Loop the leaf index */
291 for (LeafIndex = 0; LeafIndex < Leaf->Count; LeafIndex++)
292 {
293 /*
294 * Check if the main leaf is a fast
295 * leaf or a hash one.
296 */
297 if ((Leaf->Signature == CM_KEY_FAST_LEAF) ||
298 (Leaf->Signature == CM_KEY_HASH_LEAF))
299 {
300 /* It is one of the two, get the fast index */
301 FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
302
303 /*
304 * Is the subkey cell from the fast
305 * index the one we're actually
306 * searching?
307 */
308 if (FastIndex->List[LeafIndex].Cell == TargetKey)
309 {
310 HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE);
311 CmpRemoveFastIndexKeyCell(FastIndex, LeafIndex, FALSE);
312
313 /*
314 * Since this fast index actually came from the
315 * actual leaf index itself, just update its count
316 * rather than that of the fast index.
317 */
318 Leaf->Count--;
319 DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, leaf index %u)\n",
320 FastIndex, LeafIndex);
321 return TRUE;
322 }
323 }
324 else
325 {
326 /*
327 * The leaf is neither of the two. The offending
328 * cell must come directly from the normal leaf
329 * at this point.
330 */
331 if (Leaf->List[LeafIndex] == TargetKey)
332 {
333 HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE);
334 CmpRemoveIndexKeyCell(Leaf, LeafIndex);
335 DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %u)\n",
336 Leaf, LeafIndex);
337 return TRUE;
338 }
339 }
340 }
341
342 /*
343 * We have searched everywhere but we couldn't
344 * hunt the offending target key cell.
345 */
346 DPRINT1("No target key has been found to remove\n");
347 return FALSE;
348 }
349
350 /* PUBLIC FUNCTIONS ***********************************************************/
351
352 /**
353 * @brief
354 * Checks if self healing is permitted by the kernel and/or
355 * bootloader. Self healing is also triggered if such a
356 * request was prompted by the user to fix a broken hive.
357 * Such a request tipically comes from a registry repair
358 * tool such as the ReactOS Check Registry Utility.
359 *
360 * @param[in] FixHive
361 * If set to TRUE, self heal is triggered and the target
362 * hive will be fixed. Otherwise the hive will not be fixed.
363 *
364 * @return
365 * Returns TRUE if self healing is possible, FALSE otherwise.
366 */
367 BOOLEAN
368 CMAPI
CmIsSelfHealEnabled(_In_ BOOLEAN FixHive)369 CmIsSelfHealEnabled(
370 _In_ BOOLEAN FixHive)
371 {
372 PAGED_CODE();
373
374 if (FixHive)
375 return TRUE;
376
377 #if !defined(CMLIB_HOST) && !defined(_BLDR_)
378 if (CmpSelfHeal || (CmpBootType & HBOOT_TYPE_SELF_HEAL))
379 return TRUE;
380 #endif
381
382 return FALSE;
383 }
384
385 /**
386 * @brief
387 * Repairs the parent key from damage by removing the
388 * offending subkey cell.
389 *
390 * @param[in,out] Hive
391 * A pointer to a hive descriptor containing faulty data.
392 *
393 * @param[in] TargetKey
394 * The offending target cell to remove from the parent.
395 *
396 * @param[in] ParentKey
397 * The damaged parent key cell to heal.
398 *
399 * @param[in] FixHive
400 * If set to TRUE, self heal is triggered and the target
401 * hive will be fixed. Otherwise the hive will not be fixed.
402 *
403 * @return
404 * Returns TRUE if the function successfully healed the parent
405 * key, FALSE otherwise.
406 */
407 BOOLEAN
408 CMAPI
CmpRepairParentKey(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX TargetKey,_In_ HCELL_INDEX ParentKey,_In_ BOOLEAN FixHive)409 CmpRepairParentKey(
410 _Inout_ PHHIVE Hive,
411 _In_ HCELL_INDEX TargetKey,
412 _In_ HCELL_INDEX ParentKey,
413 _In_ BOOLEAN FixHive)
414 {
415 PCM_KEY_INDEX KeyIndex;
416 PCM_KEY_NODE KeyNode;
417 BOOLEAN ParentRepaired;
418
419 PAGED_CODE();
420
421 /* The target key must NEVER be NIL! */
422 ASSERT(TargetKey != HCELL_NIL);
423
424 /* Assume the parent hasn't been repaired yet */
425 ParentRepaired = FALSE;
426
427 /* Is self healing possible? */
428 if (!CmIsSelfHealEnabled(FixHive))
429 {
430 DPRINT1("Self healing not possible\n");
431 return ParentRepaired;
432 }
433
434 /* Obtain a node from the parent */
435 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
436 if (!KeyNode)
437 {
438 DPRINT1("Couldn't get the parent key node\n");
439 return ParentRepaired;
440 }
441
442 /* Obtain the index as well since we got the parent node */
443 KeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
444 if (!KeyIndex)
445 {
446 DPRINT1("Couldn't get the key index from parent node\n");
447 HvReleaseCell(Hive, ParentKey);
448 return ParentRepaired;
449 }
450
451 /* Check if this is a root */
452 if (KeyIndex->Signature == CM_KEY_INDEX_ROOT)
453 {
454 /* It is, call the specific helper to discard the damaged key down the root */
455 ParentRepaired = CmpRemoveSubkeyInRoot(Hive,
456 KeyIndex,
457 TargetKey);
458 }
459 else if ((KeyIndex->Signature == CM_KEY_INDEX_LEAF) ||
460 (KeyIndex->Signature == CM_KEY_FAST_LEAF) ||
461 (KeyIndex->Signature == CM_KEY_HASH_LEAF))
462 {
463 /* Otherwise call the leaf helper */
464 ParentRepaired = CmpRemoveSubKeyInLeaf(Hive,
465 KeyNode,
466 KeyIndex,
467 TargetKey);
468 }
469 else
470 {
471 /*
472 * Generally CmCheckRegistry detects if a key index
473 * in the subkeys list is totally broken (we understand
474 * that if its signature is not root or leaf) and it will
475 * purge the whole subkeys list in such cases. With that
476 * being said, we should never reach this code path. But
477 * if for whatever reason we reach here then something
478 * is seriously wrong.
479 */
480 DPRINT1("The key index signature is invalid (KeyIndex->Signature == %u)",
481 KeyIndex->Signature);
482 ASSERT(FALSE);
483 }
484
485 /*
486 * If we successfully removed the offending key
487 * cell mark down the parent as dirty and punt down
488 * the subkey count as well. Mark the hive as in
489 * self heal mode as well.
490 */
491 if (ParentRepaired)
492 {
493 HvMarkCellDirty(Hive, ParentKey, FALSE);
494 KeyNode->SubKeyCounts[Stable]--;
495 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
496 DPRINT1("The subkey has been removed, the parent is now repaired\n");
497 }
498
499 HvReleaseCell(Hive, KeyNode->SubKeyLists[Stable]);
500 HvReleaseCell(Hive, ParentKey);
501 return ParentRepaired;
502 }
503
504 /**
505 * @brief
506 * Repairs the parent of the node from damage due
507 * to parent cell and parent node incosistency.
508 *
509 * @param[in,out] Hive
510 * A pointer to a hive descriptor containing faulty data.
511 *
512 * @param[in] CurrentCell
513 * The current cell to be marked as dirty.
514 *
515 * @param[in] ParentCell
516 * The sane parent cell which is used by the
517 * function for new parent node assignment.
518 *
519 * @param[in,out] CellData
520 * The cell data of the current cell of which
521 * its parent node is to be repaired.
522 *
523 * @param[in] FixHive
524 * If set to TRUE, self heal is triggered and the target
525 * hive will be fixed. Otherwise the hive will not be fixed.
526 *
527 * @return
528 * Returns TRUE if the function successfully healed the
529 * parent node, FALSE otherwise.
530 */
531 BOOLEAN
532 CMAPI
CmpRepairParentNode(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ HCELL_INDEX ParentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)533 CmpRepairParentNode(
534 _Inout_ PHHIVE Hive,
535 _In_ HCELL_INDEX CurrentCell,
536 _In_ HCELL_INDEX ParentCell,
537 _Inout_ PCELL_DATA CellData,
538 _In_ BOOLEAN FixHive)
539 {
540 PAGED_CODE();
541
542 /* Is self healing possible? */
543 if (!CmIsSelfHealEnabled(FixHive))
544 {
545 DPRINT1("Self healing not possible\n");
546 return FALSE;
547 }
548
549 /*
550 * Mark the cell where we got the actual
551 * cell data as dirty and fix the node.
552 */
553 HvMarkCellDirty(Hive, CurrentCell, FALSE);
554 CellData->u.KeyNode.Parent = ParentCell;
555
556 /* Mark the hive as in self healing mode since we repaired it */
557 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
558 return TRUE;
559 }
560
561 /**
562 * @brief
563 * Repairs the key node signature from damage
564 * due to signature corruption.
565 *
566 * @param[in,out] Hive
567 * A pointer to a hive descriptor containing faulty data.
568 *
569 * @param[in] CurrentCell
570 * The current cell to be marked as dirty.
571 *
572 * @param[in,out] CellData
573 * The cell data of the current cell of which
574 * its signature is to be repaired.
575 *
576 * @param[in] FixHive
577 * If set to TRUE, self heal is triggered and the target
578 * hive will be fixed. Otherwise the hive will not be fixed.
579 *
580 * @return
581 * Returns TRUE if the function successfully healed the
582 * key node signature, FALSE otherwise.
583 */
584 BOOLEAN
585 CMAPI
CmpRepairKeyNodeSignature(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)586 CmpRepairKeyNodeSignature(
587 _Inout_ PHHIVE Hive,
588 _In_ HCELL_INDEX CurrentCell,
589 _Inout_ PCELL_DATA CellData,
590 _In_ BOOLEAN FixHive)
591 {
592 PAGED_CODE();
593
594 /* Is self healing possible? */
595 if (!CmIsSelfHealEnabled(FixHive))
596 {
597 DPRINT1("Self healing not possible\n");
598 return FALSE;
599 }
600
601 /*
602 * Mark the cell where we got the actual
603 * cell data as dirty and fix the key signature.
604 */
605 HvMarkCellDirty(Hive, CurrentCell, FALSE);
606 CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE;
607
608 /* Mark the hive as in self healing mode since we repaired it */
609 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
610 return TRUE;
611 }
612
613 /**
614 * @brief
615 * Repairs the class from damage due to class
616 * corruption within the node key.
617 *
618 * @param[in,out] Hive
619 * A pointer to a hive descriptor containing faulty data.
620 *
621 * @param[in] CurrentCell
622 * The current cell to be marked as dirty.
623 *
624 * @param[in,out] CellData
625 * The cell data of the current cell of which
626 * its class is to be repaired.
627 *
628 * @param[in] FixHive
629 * If set to TRUE, self heal is triggered and the target
630 * hive will be fixed. Otherwise the hive will not be fixed.
631 *
632 * @return
633 * Returns TRUE if the function successfully healed the
634 * class of node key, FALSE otherwise.
635 */
636 BOOLEAN
637 CMAPI
CmpRepairClassOfNodeKey(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)638 CmpRepairClassOfNodeKey(
639 _Inout_ PHHIVE Hive,
640 _In_ HCELL_INDEX CurrentCell,
641 _Inout_ PCELL_DATA CellData,
642 _In_ BOOLEAN FixHive)
643 {
644 PAGED_CODE();
645
646 /* Is self healing possible? */
647 if (!CmIsSelfHealEnabled(FixHive))
648 {
649 DPRINT1("Self healing not possible\n");
650 return FALSE;
651 }
652
653 /*
654 * Mark the cell where we got the actual
655 * cell data as dirty and fix the class field
656 * of key node.
657 */
658 HvMarkCellDirty(Hive, CurrentCell, FALSE);
659 CellData->u.KeyNode.Class = HCELL_NIL;
660 CellData->u.KeyNode.ClassLength = 0;
661
662 /* Mark the hive as in self healing mode since we repaired it */
663 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
664 return TRUE;
665 }
666
667 /**
668 * @brief
669 * Repairs the value list count of key due to
670 * corruption. The process involves by removing
671 * one damaged value less from the list.
672 *
673 * @param[in,out] Hive
674 * A pointer to a hive descriptor containing faulty data.
675 *
676 * @param[in] CurrentCell
677 * The current cell to be marked as dirty.
678 *
679 * @param[in] ListCountIndex
680 * The value count index which points to the actual
681 * value in the list to be removed.
682 *
683 * @param[in,out] ValueListData
684 * The value list cell data containing the actual list
685 * of which the damaged is to be removed from.
686 *
687 * @param[in] FixHive
688 * If set to TRUE, self heal is triggered and the target
689 * hive will be fixed. Otherwise the hive will not be fixed.
690 *
691 * @return
692 * Returns TRUE if the function successfully healed the
693 * value list count, FALSE otherwise.
694 */
695 BOOLEAN
696 CMAPI
CmpRepairValueListCount(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ ULONG ListCountIndex,_Inout_ PCELL_DATA ValueListData,_In_ BOOLEAN FixHive)697 CmpRepairValueListCount(
698 _Inout_ PHHIVE Hive,
699 _In_ HCELL_INDEX CurrentCell,
700 _In_ ULONG ListCountIndex,
701 _Inout_ PCELL_DATA ValueListData,
702 _In_ BOOLEAN FixHive)
703 {
704 PCM_KEY_NODE ValueListNode;
705
706 PAGED_CODE();
707
708 /* Is self healing possible? */
709 if (!CmIsSelfHealEnabled(FixHive))
710 {
711 DPRINT1("Self healing not possible\n");
712 return FALSE;
713 }
714
715 /*
716 * Obtain a node from the cell that we mark it as dirty.
717 * The node is that of the current cell of which its
718 * value list is being validated.
719 */
720 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell);
721 if (!ValueListNode)
722 {
723 DPRINT1("Could not get a node from the current cell\n");
724 return FALSE;
725 }
726
727 /*
728 * Mark the current cell and value list as dirty
729 * as we will be making changes onto them.
730 */
731 HvMarkCellDirty(Hive, CurrentCell, FALSE);
732 HvMarkCellDirty(Hive, ValueListNode->ValueList.List, FALSE);
733
734 /*
735 * Now remove the value from the list and mark the
736 * hive as in self healing mode.
737 */
738 CmpRemoveValueFromValueList(ValueListNode, ValueListData, ListCountIndex);
739 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
740 HvReleaseCell(Hive, CurrentCell);
741 return TRUE;
742 }
743
744 /**
745 * @brief
746 * Repairs the value list due to corruption. The
747 * process involes by purging the whole damaged
748 * list.
749 *
750 * @param[in,out] Hive
751 * A pointer to a hive descriptor containing faulty data.
752 *
753 * @param[in] CurrentCell
754 * The current cell to be marked as dirty.
755 *
756 * @param[in] FixHive
757 * If set to TRUE, self heal is triggered and the target
758 * hive will be fixed. Otherwise the hive will not be fixed.
759 *
760 * @return
761 * Returns TRUE if the function successfully healed the
762 * value list, FALSE otherwise.
763 */
764 BOOLEAN
765 CMAPI
CmpRepairValueList(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ BOOLEAN FixHive)766 CmpRepairValueList(
767 _Inout_ PHHIVE Hive,
768 _In_ HCELL_INDEX CurrentCell,
769 _In_ BOOLEAN FixHive)
770 {
771 PCM_KEY_NODE ValueListNode;
772
773 PAGED_CODE();
774
775 /* Is self healing possible? */
776 if (!CmIsSelfHealEnabled(FixHive))
777 {
778 DPRINT1("Self healing not possible\n");
779 return FALSE;
780 }
781
782 /* Obtain a node */
783 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell);
784 if (!ValueListNode)
785 {
786 DPRINT1("Could not get a node from the current cell\n");
787 return FALSE;
788 }
789
790 /* Purge out the whole list */
791 HvMarkCellDirty(Hive, CurrentCell, FALSE);
792 ValueListNode->ValueList.List = HCELL_NIL;
793 ValueListNode->ValueList.Count = 0;
794
795 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
796 HvReleaseCell(Hive, CurrentCell);
797 return TRUE;
798 }
799
800 /**
801 * @brief
802 * Repairs the subkey list count due to corruption.
803 * The process involves by fixing the count itself
804 * with a sane count.
805 *
806 * @param[in,out] Hive
807 * A pointer to a hive descriptor containing faulty data.
808 *
809 * @param[in] CurrentCell
810 * The current cell to be marked as dirty.
811 *
812 * @param[in] Count
813 * The healthy count which is used by the function
814 * to fix the subkeys list count.
815 *
816 * @param[in,out] CellData
817 * The cell data of the current cell of which its
818 * subkeys list is to be fixed.
819 *
820 * @param[in] FixHive
821 * If set to TRUE, self heal is triggered and the target
822 * hive will be fixed. Otherwise the hive will not be fixed.
823 *
824 * @return
825 * Returns TRUE if the function successfully healed the
826 * subkeys list count, FALSE otherwise.
827 */
828 BOOLEAN
829 CMAPI
CmpRepairSubKeyCounts(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ ULONG Count,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)830 CmpRepairSubKeyCounts(
831 _Inout_ PHHIVE Hive,
832 _In_ HCELL_INDEX CurrentCell,
833 _In_ ULONG Count,
834 _Inout_ PCELL_DATA CellData,
835 _In_ BOOLEAN FixHive)
836 {
837 PAGED_CODE();
838
839 /* Is self healing possible? */
840 if (!CmIsSelfHealEnabled(FixHive))
841 {
842 DPRINT1("Self healing not possible\n");
843 return FALSE;
844 }
845
846 /*
847 * Mark the cell where we got the actual
848 * cell data as dirty and fix the subkey
849 * counts.
850 */
851 HvMarkCellDirty(Hive, CurrentCell, FALSE);
852 CellData->u.KeyNode.SubKeyCounts[Stable] = Count;
853
854 /* Mark the hive as in self healing mode since we repaired it */
855 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
856 return TRUE;
857 }
858
859 /**
860 * @brief
861 * Repairs the subkey list due to corruption. The process
862 * involves by purging the whole damaged subkeys list.
863 *
864 * @param[in,out] Hive
865 * A pointer to a hive descriptor containing faulty data.
866 *
867 * @param[in] CurrentCell
868 * The current cell to be marked as dirty.
869 *
870 * @param[in,out] CellData
871 * The cell data of the current cell of which its
872 * subkeys list is to be fixed.
873 *
874 * @param[in] FixHive
875 * If set to TRUE, self heal is triggered and the target
876 * hive will be fixed. Otherwise the hive will not be fixed.
877 *
878 * @return
879 * Returns TRUE if the function successfully healed the
880 * subkeys list, FALSE otherwise.
881 */
882 BOOLEAN
883 CMAPI
CmpRepairSubKeyList(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)884 CmpRepairSubKeyList(
885 _Inout_ PHHIVE Hive,
886 _In_ HCELL_INDEX CurrentCell,
887 _Inout_ PCELL_DATA CellData,
888 _In_ BOOLEAN FixHive)
889 {
890 PAGED_CODE();
891
892 /* Is self healing possible? */
893 if (!CmIsSelfHealEnabled(FixHive))
894 {
895 DPRINT1("Self healing not possible\n");
896 return FALSE;
897 }
898
899 /*
900 * Mark the cell where we got the actual
901 * cell data as dirty and fix the subkey
902 * list.
903 */
904 HvMarkCellDirty(Hive, CurrentCell, FALSE);
905 CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
906 CellData->u.KeyNode.SubKeyCounts[Stable] = 0;
907
908 /* Mark the hive as in self healing mode since we repaired it */
909 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
910 return TRUE;
911 }
912
913 /* EOF */
914