ReactOS 0.4.15-dev-7918-g2a2556c
cmcheck.c
Go to the documentation of this file.
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 Validation
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/* STRUCTURES ****************************************************************/
13
15{
21
22/* DEFINES ******************************************************************/
23
24#define GET_HHIVE(CmHive) (&((CmHive)->Hive))
25#define GET_HHIVE_ROOT_CELL(Hive) ((Hive)->BaseBlock->RootCell)
26#define GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex) ((PHBIN)Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress)
27#define GET_CELL_BIN(Bin) ((PHCELL)((PUCHAR)Bin + sizeof(HBIN)))
28
29#define IS_CELL_VOLATILE(Cell) (HvGetCellType(Cell) == Volatile)
30
31#if !defined(CMLIB_HOST) && !defined(_BLDR_)
33#endif
34
35#define CMP_PRIOR_STACK 1
36#define CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH 512
37
38#define CMP_KEY_SIZE_THRESHOLD 0x45C
39#define CMP_VOLATILE_LIST_UNINTIALIZED 0xBAADF00D
40
41/* PRIVATE FUNCTIONS **********************************************************/
42
64static
67 _In_ PHHIVE Hive,
69 _In_ HCELL_INDEX Sibling)
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}
166
188static
191 _In_ PHHIVE Hive,
192 _In_ HCELL_INDEX CurrentCell,
193 _Inout_ PCELL_DATA CellData)
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}
229
279static
282 _In_ PHHIVE Hive,
283 _In_ HCELL_INDEX CurrentCell,
284 _In_ ULONG ListCount,
285 _In_ PCELL_DATA ValueListData,
286 _Out_ PULONG ValuesRemoved,
287 _In_ BOOLEAN FixHive)
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}
475
506static
509 _In_ PHHIVE Hive,
510 _In_ HCELL_INDEX CurrentCell,
511 _Inout_ PCELL_DATA CellData,
512 _In_ BOOLEAN FixHive)
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}
585
642static
645 _In_ PHHIVE Hive,
646 _In_ HCELL_INDEX CurrentCell,
647 _Inout_ PCELL_DATA CellData,
648 _In_ BOOLEAN FixHive,
649 _Out_ PBOOLEAN DoRepair)
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}
823
847static
848VOID
850 _In_ PHHIVE Hive,
851 _In_ HCELL_INDEX CurrentCell,
852 _Inout_ PCELL_DATA CellData,
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}
887
937static
940 _In_ PHHIVE Hive,
941 _In_ BOOLEAN SecurityDefaulted,
942 _In_ HCELL_INDEX ParentCell,
943 _In_ HCELL_INDEX CurrentCell,
945 _In_ BOOLEAN FixHive)
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}
1105
1145static
1148 _In_ PHHIVE Hive,
1150 _In_ BOOLEAN SecurityDefaulted,
1151 _In_ BOOLEAN FixHive)
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}
1386
1387/* PUBLIC FUNCTIONS ***********************************************************/
1388
1412NTAPI
1414 _In_ PHHIVE Hive,
1415 _In_ PHBIN Bin)
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}
1485
1504NTAPI
1506 _In_ PHHIVE Hive)
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}
1571
1632NTAPI
1634 _In_ PCMHIVE RegistryHive,
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}
1717
1718/* EOF */
#define PAGED_CODE()
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
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
Definition: bin.h:44
#define CMP_VOLATILE_LIST_UNINTIALIZED
Definition: cmcheck.c:39
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
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
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 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
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
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 th...
Definition: cmcheck.c:1633
#define CMP_REGISTRY_MAX_LEVELS_TREE_DEPTH
Definition: cmcheck.c:36
#define GET_HHIVE(CmHive)
Definition: cmcheck.c:24
#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
struct _CMP_REGISTRY_STACK_WORK_STATE CMP_REGISTRY_STACK_WORK_STATE
#define GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex)
Definition: cmcheck.c:26
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
#define GET_CELL_BIN(Bin)
Definition: cmcheck.c:27
#define GET_HHIVE_ROOT_CELL(Hive)
Definition: cmcheck.c:25
PCMHIVE CmiVolatileHive
Definition: cmsysini.c:16
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 _CMP_REGISTRY_STACK_WORK_STATE * PCMP_REGISTRY_STACK_WORK_STATE
#define IS_CELL_VOLATILE(Cell)
Definition: cmcheck.c:29
#define CMP_PRIOR_STACK
Definition: cmcheck.c:35
struct _CELL_DATA * PCELL_DATA
struct _CM_KEY_NODE * PCM_KEY_NODE
#define KEY_COMP_NAME
Definition: cmdata.h:35
#define CM_KEY_VALUE_SIGNATURE
Definition: cmdata.h:24
#define CM_KEY_INDEX_LEAF
Definition: cmdata.h:14
#define CM_KEY_NODE_SIGNATURE
Definition: cmdata.h:21
#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 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 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
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 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
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
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_CELL_SIZE_NOT_SANE
Definition: cmlib.h:253
#define CM_CHECK_REGISTRY_INVALID_PARAMETER
Definition: cmlib.h:238
#define CM_CHECK_REGISTRY_BAD_SUBKEY_COUNT
Definition: cmlib.h:272
#define CM_CHECK_REGISTRY_ROOT_CELL_NOT_FOUND
Definition: cmlib.h:246
#define CM_CHECK_REGISTRY_BAD_FREE_CELL
Definition: cmlib.h:243
#define CM_CHECK_REGISTRY_KEY_TOO_BIG_THAN_CELL
Definition: cmlib.h:255
#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_KEY_NAME_LENGTH_ZERO
Definition: cmlib.h:254
#define CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES
Definition: cmlib.h:228
#define CM_CHECK_REGISTRY_BAD_LEXICOGRAPHICAL_ORDER
Definition: cmlib.h:247
#define CM_CHECK_REGISTRY_STABLE_KEYS_ON_VOLATILE
Definition: cmlib.h:269
#define CM_CHECK_REGISTRY_NODE_NOT_FOUND
Definition: cmlib.h:248
#define CM_CHECK_REGISTRY_VALUE_CELL_SIZE_NOT_SANE
Definition: cmlib.h:265
#define CM_CHECK_REGISTRY_GOOD
Definition: cmlib.h:237
#define CM_CHECK_REGISTRY_HIVE_CORRUPT_SIGNATURE
Definition: cmlib.h:240
#define CM_CHECK_REGISTRY_KEY_INDEX_CELL_UNALLOCATED
Definition: cmlib.h:273
#define CM_CHECK_REGISTRY_PURGE_VOLATILES
Definition: cmlib.h:229
#define CM_CHECK_REGISTRY_BAD_KEY_NODE_PARENT
Definition: cmlib.h:256
#define CM_CHECK_REGISTRY_BIN_SIZE_OR_OFFSET_CORRUPT
Definition: cmlib.h:241
#define CM_CHECK_REGISTRY_CORRUPT_LEAF_ON_ROOT
Definition: cmlib.h:274
#define CM_CHECK_REGISTRY_ALLOCATE_MEM_STACK_FAIL
Definition: cmlib.h:245
#define TAG_REGISTRY_STACK
Definition: cmlib.h:216
#define CM_CHECK_REGISTRY_BAD_ALLOC_CELL
Definition: cmlib.h:244
#define CM_CHECK_REGISTRY_CORRUPT_LEAF_SIGNATURE
Definition: cmlib.h:275
#define ASSERT_VALUE_BIG(h, s)
Definition: cmlib.h:382
#define CM_CHECK_REGISTRY_VALIDATE_HIVE
Definition: cmlib.h:231
#define CM_CHECK_REGISTRY_KEY_CELL_NOT_ALLOCATED
Definition: cmlib.h:251
static BOOLEAN CmpIsKeyValueSmall(OUT PULONG RealLength, IN ULONG Length)
Definition: cmlib.h:390
BOOLEAN CMAPI HvIsCellAllocated(IN PHHIVE RegistryHive, IN HCELL_INDEX CellIndex)
Definition: hivecell.c:53
LONG CMAPI HvGetCellSize(PHHIVE RegistryHive, PVOID Cell)
#define CM_CHECK_REGISTRY_FIX_HIVE
Definition: cmlib.h:232
LONG NTAPI CmpCompareCompressedName(IN PCUNICODE_STRING SearchName, IN PWCHAR CompressedName, IN ULONG NameLength)
Definition: cmname.c:109
#define CM_CHECK_REGISTRY_DATA_CELL_NOT_ALLOCATED
Definition: cmlib.h:267
#define CM_CHECK_REGISTRY_SUCCESS(StatusCode)
Definition: cmlib.h:281
ULONG CM_CHECK_REGISTRY_STATUS
Definition: cmlib.h:223
#define CM_CHECK_REGISTRY_VALUE_LIST_UNALLOCATED
Definition: cmlib.h:259
BOOLEAN CMAPI HvMarkCellDirty(PHHIVE RegistryHive, HCELL_INDEX CellOffset, BOOLEAN HoldingLock)
Definition: hivecell.c:109
#define CM_CHECK_REGISTRY_BAD_KEY_NODE_SIGNATURE
Definition: cmlib.h:257
#define CM_CHECK_REGISTRY_BOOTLOADER_PURGE_VOLATILES
Definition: cmlib.h:230
#define CM_CHECK_REGISTRY_BIN_SIGNATURE_HEADER_CORRUPT
Definition: cmlib.h:242
#define CM_CHECK_REGISTRY_SUBKEY_NOT_FOUND
Definition: cmlib.h:249
#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
#define HvGetCell(Hive, Cell)
Definition: cmlib.h:452
#define CM_CHECK_REGISTRY_TREE_TOO_MANY_LEVELS
Definition: cmlib.h:250
#define CM_CHECK_REGISTRY_CORRUPT_SUBKEYS_INDEX
Definition: cmlib.h:271
#define CM_CHECK_REGISTRY_CELL_DATA_NOT_FOUND
Definition: cmlib.h:252
#define CM_CHECK_REGISTRY_SUBKEYS_LIST_UNALLOCATED
Definition: cmlib.h:270
#define CM_CHECK_REGISTRY_VALUE_LIST_DATA_NOT_FOUND
Definition: cmlib.h:260
#define CM_CHECK_REGISTRY_KEY_CLASS_UNALLOCATED
Definition: cmlib.h:258
#define CM_CHECK_REGISTRY_CORRUPT_KEY_INDEX_SIGNATURE
Definition: cmlib.h:276
#define CM_CHECK_REGISTRY_VALUE_LIST_SIZE_NOT_SANE
Definition: cmlib.h:261
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
ULONG RtlCompareUnicodeString(PUNICODE_STRING s1, PUNICODE_STRING s2, BOOLEAN UpCase)
Definition: string_lib.cpp:31
#define abs(i)
Definition: fconv.c:206
#define HV_HBIN_SIGNATURE
Definition: hivedata.h:64
#define HV_HHIVE_SIGNATURE
Definition: hivedata.h:62
@ Volatile
Definition: hivedata.h:128
@ Stable
Definition: hivedata.h:127
#define HBLOCK_SIZE
Definition: hivedata.h:42
struct _HCELL * PHCELL
#define HCELL_NIL
Definition: hivedata.h:110
#define IsFreeCell(Cell)
Definition: hivedata.h:360
ULONG HCELL_INDEX
Definition: hivedata.h:105
#define HSYS_WHISTLER_BETA1
Definition: hivedata.h:71
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
#define ASSERT(a)
Definition: mode.c:44
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4755
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
long LONG
Definition: pedump.c:60
#define DPRINT
Definition: sndvol32.h:71
CM_KEY_NODE KeyNode
Definition: cmdata.h:200
union _CELL_DATA::@4303 u
Definition: cmlib.h:316
USHORT Signature
Definition: cmdata.h:178
USHORT Count
Definition: cmdata.h:179
HCELL_INDEX List[ANYSIZE_ARRAY]
Definition: cmdata.h:180
USHORT Signature
Definition: cmdata.h:92
HCELL_INDEX Parent
Definition: cmdata.h:96
WCHAR Name[ANYSIZE_ARRAY]
Definition: cmdata.h:116
USHORT NameLength
Definition: cmdata.h:114
USHORT Flags
Definition: cmdata.h:93
LONG Size
Definition: hivedata.h:215
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
_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
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170