[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.
This commit is contained in:
George Bișoc 2023-11-09 20:40:23 +01:00
parent 27917c14ed
commit 279f8f8864
No known key found for this signature in database
GPG Key ID: 688C4FBE25D7DEF6

View File

@ -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);