[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 (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;
}

View file

@ -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();

View file

@ -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