Skip to content

Commit

Permalink
[CMLIB] Registry transactional writes.
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmks04 committed Aug 28, 2021
1 parent d5265b0 commit 8cd2d15
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 36 deletions.
2 changes: 1 addition & 1 deletion drivers/filesystems/fastfat_new/create.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ Return Value:

ULONG MatchFlags = 0;

CCB LocalCcb;
CCB LocalCcb = {0};
UNICODE_STRING Lfn;
UNICODE_STRING OrigLfn = {0};

Expand Down
4 changes: 2 additions & 2 deletions ntoskrnl/config/cminit.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,14 +545,14 @@ CmpOpenHiveFiles(IN PCUNICODE_STRING BaseName,

/* Now create the file */
Status = ZwCreateFile(Log,
DesiredAccess,
DesiredAccess | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
AttributeFlags,
ShareMode,
CreateDisposition,
IoFlags,
IoFlags | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if ((NT_SUCCESS(Status)) && (MarkAsSystemHive))
Expand Down
6 changes: 6 additions & 0 deletions sdk/lib/cmlib/cmlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,12 @@ BOOLEAN CMAPI
HvWriteHive(
PHHIVE RegistryHive);

BOOLEAN CMAPI
HvRestoreFromLog(
PHHIVE Hive,
PHBASE_BLOCK BaseBlock
);

BOOLEAN
CMAPI
HvTrackCellRef(
Expand Down
7 changes: 7 additions & 0 deletions sdk/lib/cmlib/hivedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
#define HV_HBLOCK_SIGNATURE 0x66676572 // "regf"
#define HV_HBIN_SIGNATURE 0x6e696268 // "hbin"

//
// Log identifiers
//
#define DIRTY_BLOCK 0xFF
#define DIRTY_ID 0x54524944 // DIRT
#define DIRTY_ID_SIZE 4

//
// Hive versions
//
Expand Down
168 changes: 158 additions & 10 deletions sdk/lib/cmlib/hiveinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
*/
BOOLEAN CMAPI
HvpVerifyHiveHeader(
IN PHBASE_BLOCK BaseBlock)
_In_ PHBASE_BLOCK BaseBlock,
_In_ ULONG HfileType)
{
if (BaseBlock->Signature != HV_HBLOCK_SIGNATURE ||
BaseBlock->Major != HSYS_MAJOR ||
BaseBlock->Minor < HSYS_MINOR ||
BaseBlock->Type != HFILE_TYPE_PRIMARY ||
BaseBlock->Type != HfileType ||
BaseBlock->Format != HBASE_FORMAT_MEMORY ||
BaseBlock->Cluster != 1 ||
BaseBlock->Sequence1 != BaseBlock->Sequence2 ||
Expand All @@ -31,7 +32,7 @@ HvpVerifyHiveHeader(
DPRINT1(" Signature: 0x%x, expected 0x%x; Major: 0x%x, expected 0x%x\n",
BaseBlock->Signature, HV_HBLOCK_SIGNATURE, BaseBlock->Major, HSYS_MAJOR);
DPRINT1(" Minor: 0x%x expected to be >= 0x%x; Type: 0x%x, expected 0x%x\n",
BaseBlock->Minor, HSYS_MINOR, BaseBlock->Type, HFILE_TYPE_PRIMARY);
BaseBlock->Minor, HSYS_MINOR, BaseBlock->Type, HfileType);
DPRINT1(" Format: 0x%x, expected 0x%x; Cluster: 0x%x, expected 1\n",
BaseBlock->Format, HBASE_FORMAT_MEMORY, BaseBlock->Cluster);
DPRINT1(" Sequence: 0x%x, expected 0x%x; Checksum: 0x%x, expected 0x%x\n",
Expand All @@ -44,6 +45,129 @@ HvpVerifyHiveHeader(
return TRUE;
}

BOOLEAN CMAPI
HvRestoreFromLog(
_In_ PHHIVE Hive,
_Inout_ PHBASE_BLOCK BaseBlock
)
{
HBASE_BLOCK logBaseBlock;
ULONG offset = 0;
ULONG indexInLog;
BOOLEAN isSuccess;
UCHAR dirtyVectBuffer[HSECTOR_SIZE];
UCHAR buffer[HBLOCK_SIZE];

ASSERT(sizeof(HBASE_BLOCK) >= (HSECTOR_SIZE * Hive->Cluster));

// Read log file header
isSuccess = Hive->FileRead(Hive,
HFILE_TYPE_LOG,
&offset,
&logBaseBlock,
Hive->Cluster * HSECTOR_SIZE);

if (!isSuccess)
{
DPRINT1("Read LOG file failed\n");
return FALSE;
}

// Validate log header
if (!HvpVerifyHiveHeader(&logBaseBlock, HFILE_TYPE_LOG))
{
DPRINT1("LOG header corrupted\n");
return FALSE;
}

// Read dirty blocks from log file
offset = HV_LOG_HEADER_SIZE;
isSuccess = Hive->FileRead(Hive,
HFILE_TYPE_LOG,
&offset,
dirtyVectBuffer,
HSECTOR_SIZE);

if (!isSuccess)
{
DPRINT1("Read dirty vector from LOG file failed\n");
return FALSE;
}

if (*((PULONG)dirtyVectBuffer) != DIRTY_ID)
{
DPRINT1("Wrong header in dirty block\n");
return FALSE;
}

indexInLog = 0;
// Write birty blocks
for (ULONG blockIndex = 0; blockIndex < logBaseBlock.Length / HBLOCK_SIZE; ++blockIndex)
{
if (dirtyVectBuffer[blockIndex + DIRTY_ID_SIZE] != DIRTY_BLOCK)
{
continue;
}

offset = HSECTOR_SIZE + HSECTOR_SIZE + indexInLog * HBLOCK_SIZE;
isSuccess = Hive->FileRead(Hive,
HFILE_TYPE_LOG,
&offset,
buffer,
HBLOCK_SIZE);

if (!isSuccess)
{
DPRINT1("Read hive data failed\n");
return FALSE;
}

offset = HBLOCK_SIZE + blockIndex * HBLOCK_SIZE;
isSuccess = Hive->FileWrite(Hive,
HFILE_TYPE_PRIMARY,
&offset,
buffer,
HBLOCK_SIZE);

if (!isSuccess)
{
DPRINT1("Write hive data failed\n");
return FALSE;
}

indexInLog++;
}

logBaseBlock.Type = HFILE_TYPE_PRIMARY;
logBaseBlock.CheckSum = HvpHiveHeaderChecksum(&logBaseBlock);

// Validate header
if (!HvpVerifyHiveHeader(&logBaseBlock, HFILE_TYPE_PRIMARY))
{
DPRINT1("Header corrupted\n");
return FALSE;
}

// Write header to hive
offset = 0;
isSuccess = Hive->FileWrite(Hive,
HFILE_TYPE_PRIMARY,
&offset,
&logBaseBlock,
Hive->Cluster * HSECTOR_SIZE);

if (!isSuccess)
{
DPRINT1("Write hive header failed\n");
return FALSE;
}

// Copy restored header
RtlCopyMemory(BaseBlock, &logBaseBlock, Hive->Cluster * HSECTOR_SIZE);

return TRUE;
}

/**
* @name HvpFreeHiveBins
*
Expand Down Expand Up @@ -231,16 +355,23 @@ HvpInitializeMemoryHive(
SIZE_T ChunkSize;

ChunkSize = ChunkBase->Length;
DPRINT("ChunkSize: %zx\n", ChunkSize);

if (ChunkSize < sizeof(HBASE_BLOCK) ||
!HvpVerifyHiveHeader(ChunkBase))
if (ChunkSize < sizeof(HBASE_BLOCK))
{
DPRINT1("Registry is corrupt: ChunkSize 0x%zx < sizeof(HBASE_BLOCK) 0x%zx, "
"or HvpVerifyHiveHeader() failed\n", ChunkSize, sizeof(HBASE_BLOCK));
DPRINT1("Registry is corrupt: ChunkSize 0x%zx < sizeof(HBASE_BLOCK) 0x%zx\n", ChunkSize, sizeof(HBASE_BLOCK));
return STATUS_REGISTRY_CORRUPT;
}

if (!HvpVerifyHiveHeader(ChunkBase, HFILE_TYPE_PRIMARY))
{
DPRINT1("HvpVerifyHiveHeader() failed. Try restore.\n");
if (!HvRestoreFromLog(Hive, ChunkBase))
{
DPRINT1("Restore from LOG Failed\n");
return STATUS_REGISTRY_CORRUPT;
}
}

/* Allocate the base block */
Hive->BaseBlock = HvpAllocBaseBlockAligned(Hive, FALSE, TAG_CM);
if (Hive->BaseBlock == NULL)
Expand Down Expand Up @@ -345,8 +476,16 @@ HvpInitializeFlatHive(
PHHIVE Hive,
PHBASE_BLOCK ChunkBase)
{
if (!HvpVerifyHiveHeader(ChunkBase))
if (!HvpVerifyHiveHeader(ChunkBase, HFILE_TYPE_PRIMARY))
{
DPRINT1("HvpVerifyHiveHeader() failed. Try restore.\n");
if (!HvRestoreFromLog(Hive, ChunkBase))
{
DPRINT1("Restore from LOG Failed\n");
return STATUS_REGISTRY_CORRUPT;
}
return STATUS_REGISTRY_CORRUPT;
}

/* Setup hive data */
Hive->BaseBlock = ChunkBase;
Expand Down Expand Up @@ -403,7 +542,16 @@ HvpGetHiveHeader(IN PHHIVE Hive,
if (!Result) return NotHive;

/* Do validation */
if (!HvpVerifyHiveHeader(BaseBlock)) return NotHive;
if (!HvpVerifyHiveHeader(BaseBlock, HFILE_TYPE_PRIMARY))
{
DPRINT1("HvpVerifyHiveHeader() failed. Try restore.\n");
if (!HvRestoreFromLog(Hive, BaseBlock))
{
DPRINT1("Restore from LOG Failed\n");
return NotHive;
}
DPRINT1("Hive restored\n");
}

/* Return information */
*HiveBaseBlock = BaseBlock;
Expand Down
53 changes: 30 additions & 23 deletions sdk/lib/cmlib/hivewrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,8 @@ HvpWriteLog(
ULONG LastIndex;
PVOID BlockPtr;
BOOLEAN Success;
static ULONG PrintCount = 0;

if (PrintCount++ == 0)
{
UNIMPLEMENTED;
}
return TRUE;


ASSERT(RegistryHive->ReadOnly == FALSE);
ASSERT(RegistryHive->BaseBlock->Length ==
RegistryHive->Storage[Stable].Length * HBLOCK_SIZE);
Expand All @@ -42,18 +36,16 @@ HvpWriteLog(
return FALSE;
}

BitmapSize = RegistryHive->DirtyVector.SizeOfBitMap;
BufferSize = HV_LOG_HEADER_SIZE + sizeof(ULONG) + BitmapSize;
BufferSize = ROUND_UP(BufferSize, HBLOCK_SIZE);

DPRINT("Bitmap size %u buffer size: %u\n", BitmapSize, BufferSize);

Buffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM);
BitmapSize = ROUND_UP(sizeof(ULONG) + RegistryHive->DirtyVector.SizeOfBitMap, HSECTOR_SIZE);
BufferSize = HV_LOG_HEADER_SIZE + BitmapSize;
Buffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM);
if (Buffer == NULL)
{
return FALSE;
}

RtlZeroMemory(Buffer, BufferSize);

/* Update first update counter and CheckSum */
RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG;
RegistryHive->BaseBlock->Sequence1++;
Expand All @@ -63,9 +55,23 @@ HvpWriteLog(
/* Copy hive header */
RtlCopyMemory(Buffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE);
Ptr = Buffer + HV_LOG_HEADER_SIZE;
RtlCopyMemory(Ptr, "DIRT", 4);
Ptr += 4;
RtlCopyMemory(Ptr, RegistryHive->DirtyVector.Buffer, BitmapSize);
*((PULONG)Ptr) = DIRTY_ID;
Ptr += DIRTY_ID_SIZE;

// Mark dirty blocks as "FF" - 1 bit per sector
BlockIndex = 0;
while (BlockIndex < RegistryHive->Storage[Stable].Length)
{
LastIndex = BlockIndex;
BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
if (BlockIndex == ~0U || BlockIndex < LastIndex)
{
break;
}

Ptr[BlockIndex] = DIRTY_BLOCK;
BlockIndex++;
}

/* Write hive block and block bitmap */
FileOffset = 0;
Expand Down Expand Up @@ -104,12 +110,13 @@ HvpWriteLog(
FileOffset += HBLOCK_SIZE;
}

Success = RegistryHive->FileSetSize(RegistryHive, HFILE_TYPE_LOG, FileOffset, FileOffset);
if (!Success)
{
DPRINT("FileSetSize failed\n");
return FALSE;
}
//TODO: Check this function. In some cases log file can be corrrupted
//Success = RegistryHive->FileSetSize(RegistryHive, HFILE_TYPE_LOG, FileOffset, FileOffset);
//if (!Success)
//{
// DPRINT("FileSetSize failed\n");
// return FALSE;
//}

/* Flush the log file */
Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
Expand Down

0 comments on commit 8cd2d15

Please sign in to comment.