https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d61c00c2522f9002593303...
commit d61c00c2522f9002593303c684b1d716f1875da6 Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Sun Oct 21 23:08:51 2018 +0200 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@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