From 21b0ecacdca04307f701632376dab5f58ae04765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?George=20Bi=C8=99oc?= Date: Sat, 2 Jul 2022 22:44:06 +0200 Subject: [PATCH] [SDK][CMLIB] Implement registry check validation Description to be added... CORE-9195 CORE-6762 --- ntoskrnl/config/cmcheck.c | 27 ---- ntoskrnl/include/internal/cm.h | 10 -- ntoskrnl/ntos.cmake | 1 - sdk/lib/cmlib/CMakeLists.txt | 1 + sdk/lib/cmlib/cmcheck.c | 234 +++++++++++++++++++++++++++++++++ sdk/lib/cmlib/cmlib.h | 64 +++++++++ 6 files changed, 299 insertions(+), 38 deletions(-) delete mode 100644 ntoskrnl/config/cmcheck.c create mode 100644 sdk/lib/cmlib/cmcheck.c diff --git a/ntoskrnl/config/cmcheck.c b/ntoskrnl/config/cmcheck.c deleted file mode 100644 index 4172dddc3321a..0000000000000 --- a/ntoskrnl/config/cmcheck.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * PROJECT: ReactOS Kernel - * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmcheck.c - * PURPOSE: Configuration Manager - Hive and Key Validation - * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) - */ - -/* INCLUDES ******************************************************************/ - -#include "ntoskrnl.h" -#define NDEBUG -#include "debug.h" - -/* GLOBALS *******************************************************************/ - -/* FUNCTIONS *****************************************************************/ - -ULONG -NTAPI -CmCheckRegistry(IN PCMHIVE RegistryHive, - IN ULONG Flags) -{ - /* FIXME: HACK! */ - DPRINT1("CmCheckRegistry(0x%p, %lu) is UNIMPLEMENTED!\n", RegistryHive, Flags); - return 0; -} diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h index 423c65b9a8d7f..d79da2447b814 100644 --- a/ntoskrnl/include/internal/cm.h +++ b/ntoskrnl/include/internal/cm.h @@ -562,16 +562,6 @@ CmpCompareNewValueDataAgainstKCBCache( IN ULONG DataSize ); -// -// Registry Validation Functions -// -ULONG -NTAPI -CmCheckRegistry( - IN PCMHIVE Hive, - IN ULONG Flags -); - // // Hive List Routines // diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake index af8217bc4806d..55081ba9cb427 100644 --- a/ntoskrnl/ntos.cmake +++ b/ntoskrnl/ntos.cmake @@ -48,7 +48,6 @@ list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmalloc.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmapi.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmboot.c - ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmcheck.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmconfig.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmcontrl.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmdata.c diff --git a/sdk/lib/cmlib/CMakeLists.txt b/sdk/lib/cmlib/CMakeLists.txt index d69202ba12d22..5ba9f2522ad5a 100644 --- a/sdk/lib/cmlib/CMakeLists.txt +++ b/sdk/lib/cmlib/CMakeLists.txt @@ -4,6 +4,7 @@ add_definitions( -DNASSERT) list(APPEND SOURCE + cmcheck.c cminit.c cmindex.c cmkeydel.c diff --git a/sdk/lib/cmlib/cmcheck.c b/sdk/lib/cmlib/cmcheck.c new file mode 100644 index 0000000000000..792351edd82ed --- /dev/null +++ b/sdk/lib/cmlib/cmcheck.c @@ -0,0 +1,234 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Configuration Manager Library - Registry Validation + * COPYRIGHT: Copyright 2022 George Bișoc + */ + +/* INCLUDES ******************************************************************/ + +#include "cmlib.h" +#define NDEBUG +#include + +/* DEFINES ******************************************************************/ + +#define GET_HHIVE(CmHive) (&((CmHive)->Hive)) +#define GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex) ((PHBIN)Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress) +#define GET_CELL_BIN(Bin) ((PHCELL)(Bin +1)) + +#if !defined(CMLIB_HOST) && !defined(_BLDR_) +extern PCMHIVE CmiVolatileHive; +#endif + +/* PRIVATE FUNCTIONS **********************************************************/ + +BOOLEAN +NTAPI +CmpValidateSDsOfHive( + _In_ PHHIVE Hive, + _Out_ PBOOLEAN SecurityDefaulted) +{ + // TODO + UNREFERENCED_PARAMETER(Hive); + UNREFERENCED_PARAMETER(SecurityDefaulted); + return TRUE; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +CM_CHECK_REGISTRY_STATUS +NTAPI +HvValidateBin( + _In_ PHBIN Bin, + _In_ PHHIVE Hive, + _In_ ULONG StorageIndex, + _In_ ULONG StorageLength) +{ + HCELL_INDEX FileOffset; + PHCELL Cell, Basket; + + /* Sanity checks */ + ASSERT(Bin); + ASSERT(Hive); + ASSERT(StorageLength != 0); + + /* + * The block offset is the current storage space + * times the block size. + */ + FileOffset = Hive->Storage[StorageIndex].Length * + HBLOCK_SIZE; + + /* Ensure that this bin we got has valid header */ + if (Bin->Signature != HV_HBIN_SIGNATURE || + Bin->Size > StorageLength || + Bin->FileOffset != FileOffset) + { + DPRINT1("HvValidateBin(): The bin's header is corrupt!\n"); + return CM_CHECK_REGISTRY_BIN_HEADER_CORRUPT; + } + + /* + * Walk over all the cells from this bin and + * validate that they're consistent with the bin. + * Namely we want that each cell from this bin doesn't + * have a bogus size. + */ + Cell = GET_CELL_BIN(Bin); + Basket = (PHCELL)((PULONG)Bin + Bin->Size); + while (Cell < Basket) + { + /* Does this cell have some free space? */ + if (Cell->Size > 0) + { + /* + * This cell indeed is free, check that + * the size of this cell is not bogus. + */ + if (Cell->Size > Bin->Size) + { + /* + * This cell has too much free space that + * exceeds the boundary of the bin size. + */ + DPRINT1("HvValidateBin(): The free cell exceeds the bin size (cell: %p, cell size %d, bin size %lu)\n", + Cell, Cell->Size, Bin->Size); + return CM_CHECK_REGISTRY_FREE_CELL_EXCEEDS_BIN_SIZE; + } + } + else if (Cell->Size < 0) + { + /* + * This cell is allocated, make sure that + * the size of this cell is not bogus. + */ + if (abs(Cell->Size) > Bin->Size) + { + /* + * This cell allocated too much space + * that exceeds the boundary of the + * bin size. + */ + DPRINT1("HvValidateBin(): The allocated cell exceeds the bin size (cell: %p, cell size %d, bin size %lu)\n", + Cell, abs(Cell->Size), Bin->Size); + return CM_CHECK_REGISTRY_ALLOC_CELL_EXCEEDS_BIN_SIZE; + } + } + else + { + /* + * If we reach this path then the cell is + * neither allocated nor free (Size == 0). + * Such a cell of this kind is a no go for + * this bin so bail out. + */ + DPRINT1("HvValidateBin(): This cell is neither allocated nor free!\n"); + return CM_CHECK_REGISTRY_BAD_CELL_IN_BIN; + } + + /* Go to the next cell */ + Cell = (PHCELL)((PULONG)Cell + abs(Cell->Size)); + } + + return CM_CHECK_REGISTRY_GOOD; +} + +CM_CHECK_REGISTRY_STATUS +NTAPI +HvValidateHive( + _In_ PHHIVE Hive) +{ + ULONG CmStatusCode; + ULONG StorageIndex; + ULONG BlockIndex; + ULONG StorageLength; + PHBIN Bin; + + /* Sanity check */ + ASSERT(Hive); + + /* Is the hive signature valid? */ + if (Hive->Signature != HV_HHIVE_SIGNATURE) + { + /* Someone sent Fat Man type of nuclear bomb to this hive, bail out */ + DPRINT1("HvValidateHive(): Hive's signature corrupted (signature %lu)\n", Hive->Signature); + return CM_CHECK_REGISTRY_HIVE_CORRUPT_SIGNATURE; + } + + /* + * Now loop each bin in the storage of this + * hive. + */ + for (StorageIndex = 0; StorageIndex < Hive->StorageTypeCount; StorageIndex++) + { + for (BlockIndex = 0; BlockIndex < Hive->Storage[StorageIndex].Length; BlockIndex++) + { + /* Go to the next if this bin does not exist */ + if (Hive->Storage[StorageIndex].BlockList[BlockIndex].BinAddress == (ULONG_PTR)NULL) + { + continue; + } + + /* Get the storage length at this index */ + StorageLength = Hive->Storage[StorageIndex].Length; + + /* Capture this bin and begin validate its contents */ + Bin = GET_HHIVE_BIN(Hive, StorageIndex, BlockIndex); + CmStatusCode = HvValidateBin(Bin, Hive, StorageIndex, StorageLength); + if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode)) + { + DPRINT1("HvValidateHive(): This bin is not valid (bin %p)\n", Bin); + return CmStatusCode; + } + } + } + + return CM_CHECK_REGISTRY_GOOD; +} + +CM_CHECK_REGISTRY_STATUS +NTAPI +CmCheckRegistry( + _In_ PCMHIVE RegistryHive, + _In_ ULONG Flags) +{ + ULONG CmStatusCode; + PHHIVE Hive; + + /* Make sure the submitted flag is valid */ + ASSERT(Flags & CM_CHECK_REGISTRY_VALID_FLAGS); + +#if !defined(CMLIB_HOST) && !defined(_BLDR_) + /* + * If this CM hive that we got is a volatile + * hive (aka master hive which is what it's called + * on Windows) then registry validation checks is + * not necessary. + */ + if (RegistryHive == CmiVolatileHive) + { + DPRINT("CmCheckRegistry(): This is master registry hive, don't do anything!\n"); + return CM_CHECK_REGISTRY_GOOD; + } +#endif + + /* + * Obtain the hive and check if the caller wants + * that the hive to be validated. + */ + Hive = GET_HHIVE(RegistryHive); + if (Flags & CM_CHECK_REGISTRY_VALIDATE_HIVE) + { + CmStatusCode = HvValidateHive(Hive); + if (!CM_CHECK_REGISTRY_SUCCESS(CmStatusCode)) + { + DPRINT1("CmCheckRegistry(): The hive is not valid (hive pointer %p)!\n", Hive); + return CmStatusCode; + } + } + + // TODO + + return CM_CHECK_REGISTRY_GOOD; +} diff --git a/sdk/lib/cmlib/cmlib.h b/sdk/lib/cmlib/cmlib.h index d1b8c0656fe44..275664e7adb8f 100644 --- a/sdk/lib/cmlib/cmlib.h +++ b/sdk/lib/cmlib/cmlib.h @@ -211,6 +211,42 @@ #define CMAPI NTAPI +// +// Check Registry status type definition +// +#define CM_CHECK_REGISTRY_STATUS ULONG + +// +// Check Registry flags +// +#define CM_CHECK_REGISTRY_PURGE 0x1 +#define CM_CHECK_REGISTRY_MANDATORY_PURGE 0x2 +#define CM_CHECK_REGISTRY_BOOTLOADER_PURGE 0x4 +#define CM_CHECK_REGISTRY_SYSTEM_PURGE 0x8 +#define CM_CHECK_REGISTRY_VALIDATE_HIVE 0x10 + +#define CM_CHECK_REGISTRY_VALID_FLAGS (CM_CHECK_REGISTRY_PURGE | \ + CM_CHECK_REGISTRY_MANDATORY_PURGE | \ + CM_CHECK_REGISTRY_BOOTLOADER_PURGE | \ + CM_CHECK_REGISTRY_SYSTEM_PURGE | \ + CM_CHECK_REGISTRY_VALIDATE_HIVE) + +// +// Check Registry success macro +// +#define CM_CHECK_REGISTRY_SUCCESS(StatusCode) ((ULONG)(StatusCode) >= 0) + +// +// Check Registry status codes +// +#define CM_CHECK_REGISTRY_GOOD 0 +#define CM_CHECK_REGISTRY_SD_INVALID 1000 +#define CM_CHECK_REGISTRY_HIVE_CORRUPT_SIGNATURE 2000 +#define CM_CHECK_REGISTRY_BIN_HEADER_CORRUPT 3000 +#define CM_CHECK_REGISTRY_FREE_CELL_EXCEEDS_BIN_SIZE 3010 +#define CM_CHECK_REGISTRY_ALLOC_CELL_EXCEEDS_BIN_SIZE 3020 +#define CM_CHECK_REGISTRY_BAD_CELL_IN_BIN 3030 + #include #include #include "hivedata.h" @@ -496,6 +532,34 @@ CmPrepareHive( /* NT-style Public Cm functions */ +// +// Check Registry Routines +// +BOOLEAN +NTAPI +CmpValidateSDsOfHive( + _In_ PHHIVE Hive, + _Out_ PBOOLEAN SecurityDefaulted); + +CM_CHECK_REGISTRY_STATUS +NTAPI +HvValidateBin( + _In_ PHBIN Bin, + _In_ PHHIVE Hive, + _In_ ULONG StorageIndex, + _In_ ULONG StorageLength); + +CM_CHECK_REGISTRY_STATUS +NTAPI +HvValidateHive( + _In_ PHHIVE Hive); + +CM_CHECK_REGISTRY_STATUS +NTAPI +CmCheckRegistry( + _In_ PCMHIVE RegistryHive, + _In_ ULONG Flags); + // // Cell Index Routines //