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 Sep 2, 2021
1 parent d5265b0 commit 2e0e7f2
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 26 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
149 changes: 143 additions & 6 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,133 @@ HvpVerifyHiveHeader(
return TRUE;
}

/**
* @name HvRestoreFromLog
*
* Function to restore hive from log.
*/
BOOLEAN CMAPI
HvRestoreFromLog(
IN PHHIVE Hive,
IN OUT 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 @@ -234,7 +362,7 @@ HvpInitializeMemoryHive(
DPRINT("ChunkSize: %zx\n", ChunkSize);

if (ChunkSize < sizeof(HBASE_BLOCK) ||
!HvpVerifyHiveHeader(ChunkBase))
!HvpVerifyHiveHeader(ChunkBase, HFILE_TYPE_PRIMARY))
{
DPRINT1("Registry is corrupt: ChunkSize 0x%zx < sizeof(HBASE_BLOCK) 0x%zx, "
"or HvpVerifyHiveHeader() failed\n", ChunkSize, sizeof(HBASE_BLOCK));
Expand Down Expand Up @@ -345,7 +473,7 @@ HvpInitializeFlatHive(
PHHIVE Hive,
PHBASE_BLOCK ChunkBase)
{
if (!HvpVerifyHiveHeader(ChunkBase))
if (!HvpVerifyHiveHeader(ChunkBase, HFILE_TYPE_PRIMARY))
return STATUS_REGISTRY_CORRUPT;

/* Setup hive data */
Expand Down Expand Up @@ -403,7 +531,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
43 changes: 26 additions & 17 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,15 @@ HvpWriteLog(
FileOffset += HBLOCK_SIZE;
}

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

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

0 comments on commit 2e0e7f2

Please sign in to comment.