https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d61c00c2522f9002593303c684b1d716f1875da6

commit d61c00c2522f9002593303c684b1d716f1875da6
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Sun Oct 21 23:08:51 2018 +0200
Commit:     Hermès Bélusca-Maïto <[email protected]>
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

Reply via email to