https://git.reactos.org/?p=reactos.git;a=commitdiff;h=279f8f88644246b95521f…
commit 279f8f88644246b95521f2deb7c99badcf726f12
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Thu Nov 9 20:40:23 2023 +0100
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Nov 19 20:44:29 2023 +0100
[CMLIB] Fix the bin during hive initialization from memory if it's corrupt
As we iterate over the chunk hive data pointer for hive bins that we are going
to enlist, we might encounter one or several bins that would get corrupted
during a premature abortion of a registry writing operation such as due to
a power outage of the system, hardware malfunction, etc.
Corruption at the level of hive bins is nasty because they contain actual cell
data of registry information such as keys, values etc. Assuming a bin is corrupt
in part we can fix it by recovering some of the bin properties that, theoretically,
could be fixed -- namely the signature, size and offset.
For size and offset we are more or less safe because a bin typically has a size
of a block, and the offset is the coordinate index of where a hive bin should lay
at.
---
sdk/lib/cmlib/hiveinit.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/sdk/lib/cmlib/hiveinit.c b/sdk/lib/cmlib/hiveinit.c
index 0b03ddf258b..a89a5050c21 100644
--- a/sdk/lib/cmlib/hiveinit.c
+++ b/sdk/lib/cmlib/hiveinit.c
@@ -368,13 +368,31 @@ HvpInitializeMemoryHive(
{
Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HBLOCK_SIZE);
if (Bin->Signature != HV_HBIN_SIGNATURE ||
- (Bin->Size % HBLOCK_SIZE) != 0)
+ (Bin->Size % HBLOCK_SIZE) != 0 ||
+ (Bin->FileOffset / HBLOCK_SIZE) != BlockIndex)
{
- DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size
0x%x\n",
+ /*
+ * Bin is toast but luckily either the signature, size or offset
+ * is out of order. For the signature it is obvious what we are going
+ * to do, for the offset we are re-positioning the bin back to where it
+ * was and for the size we will set it up to a block size, since
technically
+ * a hive bin is large as a block itself to accommodate cells.
+ */
+ if (!CmIsSelfHealEnabled(FALSE))
+ {
+ DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size 0x%x.
Self-heal not possible!\n",
(unsigned long)BlockIndex, (unsigned)Bin->Signature,
(unsigned)Bin->Size);
- Hive->Free(Hive->Storage[Stable].BlockList, 0);
- Hive->Free(Hive->BaseBlock, Hive->BaseBlockAlloc);
- return STATUS_REGISTRY_CORRUPT;
+ Hive->Free(Hive->Storage[Stable].BlockList, 0);
+ Hive->Free(Hive->BaseBlock, Hive->BaseBlockAlloc);
+ return STATUS_REGISTRY_CORRUPT;
+ }
+
+ /* Fix this bin */
+ Bin->Signature = HV_HBIN_SIGNATURE;
+ Bin->Size = HBLOCK_SIZE;
+ Bin->FileOffset = BlockIndex * HBLOCK_SIZE;
+ ChunkBase->BootType |= HBOOT_TYPE_SELF_HEAL;
+ DPRINT1("Bin at index %lu is corrupt and it has been repaired!\n",
(unsigned long)BlockIndex);
}
NewBin = Hive->Allocate(Bin->Size, TRUE, TAG_CM);