[NTOS:CM] Implement more support for force-unloading registry hives.

CORE-13448 CORE-10705
This commit is contained in:
Hermès Bélusca-Maïto 2018-10-21 23:08:51 +02:00
parent 16752875db
commit d61c00c252
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
3 changed files with 64 additions and 12 deletions

View file

@ -2221,7 +2221,7 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
{ {
if (Flags != REG_FORCE_UNLOAD) 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 */ /* There are open subkeys but we don't force hive unloading, fail */
Hive->HiveFlags &= ~HIVE_IS_UNLOADING; Hive->HiveFlags &= ~HIVE_IS_UNLOADING;
@ -2230,7 +2230,13 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
} }
else 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; 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 */ /* Clean up information we have on the subkey */
CmpCleanUpSubKeyInfo(Kcb->ParentKcb); CmpCleanUpSubKeyInfo(Kcb->ParentKcb);
@ -2272,6 +2282,10 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
/* Remove the hive from the hive file list */ /* Remove the hive from the hive file list */
CmpRemoveFromHiveFileList(CmHive); CmpRemoveFromHiveFileList(CmHive);
/**
** NOTE:
** The following code is mostly equivalent to what we "call" CmpDestroyHive()
**/
/* Destroy the security descriptor cache */ /* Destroy the security descriptor cache */
CmpDestroySecurityCache(CmHive); CmpDestroySecurityCache(CmHive);
@ -2296,8 +2310,10 @@ CmUnloadKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
ULONG ULONG
NTAPI NTAPI
CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb, CmpEnumerateOpenSubKeys(
IN BOOLEAN RemoveEmptyCacheEntries) IN PCM_KEY_CONTROL_BLOCK RootKcb,
IN BOOLEAN RemoveEmptyCacheEntries,
IN BOOLEAN DereferenceOpenedEntries)
{ {
PCM_KEY_HASH Entry; PCM_KEY_HASH Entry;
PCM_KEY_CONTROL_BLOCK CachedKcb; PCM_KEY_CONTROL_BLOCK CachedKcb;
@ -2306,9 +2322,9 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
ULONG i, j; ULONG i, j;
ULONG SubKeys = 0; 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) if (RootKcb->RefCount == 1)
{ {
DPRINT("Open sub keys: 0\n"); DPRINT("Open sub keys: 0\n");
@ -2347,10 +2363,43 @@ CmCountOpenSubKeys(IN PCM_KEY_CONTROL_BLOCK RootKcb,
if (CachedKcb->RefCount > 0) 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 */ /* Count the current hash entry if it is in use */
SubKeys++; SubKeys++;
} }
else if ((CachedKcb->RefCount == 0) && (RemoveEmptyCacheEntries != FALSE)) else if ((CachedKcb->RefCount == 0) && RemoveEmptyCacheEntries)
{ {
/* Remove the current key from the delayed close list */ /* Remove the current key from the delayed close list */
CmpRemoveFromDelayedClose(CachedKcb); 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; return SubKeys;
} }

View file

@ -1542,8 +1542,8 @@ NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
} }
/* Call the internal API */ /* Call the internal API */
*HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock, *HandleCount = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock,
FALSE); FALSE, FALSE);
/* Unlock the registry */ /* Unlock the registry */
CmpUnlockRegistry(); CmpUnlockRegistry();

View file

@ -1357,9 +1357,10 @@ CmUnloadKey(
ULONG ULONG
NTAPI NTAPI
CmCountOpenSubKeys( CmpEnumerateOpenSubKeys(
IN PCM_KEY_CONTROL_BLOCK RootKcb, IN PCM_KEY_CONTROL_BLOCK RootKcb,
IN BOOLEAN RemoveEmptyCacheEntries IN BOOLEAN RemoveEmptyCacheEntries,
IN BOOLEAN DereferenceOpenedEntries
); );
HCELL_INDEX HCELL_INDEX