https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d61c00c2522f900259330…
commit d61c00c2522f9002593303c684b1d716f1875da6
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Oct 21 23:08:51 2018 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Mon Oct 22 00:05:13 2018 +0200
[NTOS:CM] Implement more support for force-unloading registry hives.
CORE-13448 CORE-10705
---
ntoskrnl/config/cmapi.c | 67 +++++++++++++++++++++++++++++++++++++-----
ntoskrnl/config/ntapi.c | 4 +--
ntoskrnl/include/internal/cm.h | 5 ++--
3 files changed, 64 insertions(+), 12 deletions(-)
diff --git a/ntoskrnl/config/cmapi.c b/ntoskrnl/config/cmapi.c
index 3b476d8c8e..84e0f11b91 100644
--- a/ntoskrnl/config/cmapi.c
+++ b/ntoskrnl/config/cmapi.c
@@ -2221,7 +2221,7 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
{
if (Flags != REG_FORCE_UNLOAD)
{
- if (CmCountOpenSubKeys(Kcb, FALSE) != 0)
+ if (CmpEnumerateOpenSubKeys(Kcb, FALSE, FALSE) != 0)
{
/* There are open subkeys but we don't force hive unloading, fail */
Hive->HiveFlags &= ~HIVE_IS_UNLOADING;
@@ -2230,7 +2230,13 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
}
else
{
- DPRINT1("CmUnloadKey: Force unloading is UNIMPLEMENTED, expect dangling KCBs problems!\n");
+ DPRINT1("CmUnloadKey: Force unloading is HALF-IMPLEMENTED, expect dangling KCBs problems!\n");
+ if (CmpEnumerateOpenSubKeys(Kcb, TRUE, TRUE) != 0)
+ {
+ /* There are open subkeys that we cannot force to unload, fail */
+ Hive->HiveFlags &= ~HIVE_IS_UNLOADING;
+ return STATUS_CANNOT_DELETE;
+ }
}
}
@@ -2247,6 +2253,10 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
return STATUS_INSUFFICIENT_RESOURCES;
}
+ /* Flush any notifications if we force hive unloading */
+ if (Flags == REG_FORCE_UNLOAD)
+ CmpFlushNotifiesOnKeyBodyList(Kcb, TRUE); // Lock is already held
+
/* Clean up information we have on the subkey */
CmpCleanUpSubKeyInfo(Kcb->ParentKcb);
@@ -2272,6 +2282,10 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
/* Remove the hive from the hive file list */
CmpRemoveFromHiveFileList(CmHive);
+/**
+ ** NOTE:
+ ** The following code is mostly equivalent to what we "call" CmpDestroyHive()
+ **/
/* Destroy the security descriptor cache */
CmpDestroySecurityCache(CmHive);
@@ -2296,8 +2310,10 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
ULONG
NTAPI
-CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
- IN BOOLEAN RemoveEmptyCacheEntries)
+CmpEnumerateOpenSubKeys(
+ IN PCM_KEY_CONTROL_BLOCK RootKcb,
+ IN BOOLEAN RemoveEmptyCacheEntries,
+ IN BOOLEAN DereferenceOpenedEntries)
{
PCM_KEY_HASH Entry;
PCM_KEY_CONTROL_BLOCK CachedKcb;
@@ -2306,9 +2322,9 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
ULONG i, j;
ULONG SubKeys = 0;
- DPRINT("CmCountOpenSubKeys() called\n");
+ DPRINT("CmpEnumerateOpenSubKeys() called\n");
- /* The root key is the only referenced key. There are no refereced sub keys. */
+ /* The root key is the only referenced key. There are no referenced sub keys. */
if (RootKcb->RefCount == 1)
{
DPRINT("Open sub keys: 0\n");
@@ -2347,10 +2363,43 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
if (CachedKcb->RefCount > 0)
{
+ DPRINT1("Found a sub key pointing to '%.*s', RefCount = %u\n",
+ CachedKcb->NameBlock->NameLength, CachedKcb->NameBlock->Name,
+ CachedKcb->RefCount);
+
+ /* If we dereference opened KCBs, don't touch read-only keys */
+ if (DereferenceOpenedEntries &&
+ !(CachedKcb->ExtFlags & CM_KCB_READ_ONLY_KEY))
+ {
+ /* Registry needs to be locked down */
+ CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
+
+ /* Flush any notifications */
+ CmpFlushNotifiesOnKeyBodyList(CachedKcb, TRUE); // Lock is already held
+
+ /* Clean up information we have on the subkey */
+ CmpCleanUpSubKeyInfo(CachedKcb->ParentKcb);
+
+ /* Get and cache the next cache entry */
+ // Entry = Entry->NextHash;
+ Entry = CachedKcb->NextHash;
+
+ /* Set the KCB in delete mode and remove it */
+ CachedKcb->Delete = TRUE;
+ CmpRemoveKeyControlBlock(CachedKcb);
+
+ /* Clear the cell */
+ CachedKcb->KeyCell = HCELL_NIL;
+
+ /* Restart with the next cache entry */
+ continue;
+ }
+ /* Else, the key cannot be dereferenced, and we count it as in use */
+
/* Count the current hash entry if it is in use */
SubKeys++;
}
- else if ((CachedKcb->RefCount == 0) && (RemoveEmptyCacheEntries != FALSE))
+ else if ((CachedKcb->RefCount == 0) && RemoveEmptyCacheEntries)
{
/* Remove the current key from the delayed close list */
CmpRemoveFromDelayedClose(CachedKcb);
@@ -2370,7 +2419,9 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
}
}
- DPRINT("Open sub keys: %u\n", SubKeys);
+ if (SubKeys > 0)
+ DPRINT1("Open sub keys: %u\n", SubKeys);
+
return SubKeys;
}
diff --git a/ntoskrnl/config/ntapi.c b/ntoskrnl/config/ntapi.c
index 7a5376f02c..5be3a279d8 100644
--- a/ntoskrnl/config/ntapi.c
+++ b/ntoskrnl/config/ntapi.c
@@ -1542,8 +1542,8 @@ NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
}
/* Call the internal API */
- *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock,
- FALSE);
+ *HandleCount = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock,
+ FALSE, FALSE);
/* Unlock the registry */
CmpUnlockRegistry();
diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h
index a3f801df1f..12ccb1c8bb 100644
--- a/ntoskrnl/include/internal/cm.h
+++ b/ntoskrnl/include/internal/cm.h
@@ -1357,9 +1357,10 @@ CmUnloadKey(
ULONG
NTAPI
-CmCountOpenSubKeys(
+CmpEnumerateOpenSubKeys(
IN PCM_KEY_CONTROL_BLOCK RootKcb,
- IN BOOLEAN RemoveEmptyCacheEntries
+ IN BOOLEAN RemoveEmptyCacheEntries,
+ IN BOOLEAN DereferenceOpenedEntries
);
HCELL_INDEX