Fixed reference counting in CmiConnectHive and CmiDisconnectHive.

No longer need hacks to check reference counts.
Deleted a ton of wierd code.
Fixed bug where we allocated uninitialized memory for child nodes we never
populated.
Now reference counting mirrors pointers exactly:
 - Hold one reference for the parent key pointer
 - Hold one reference for the list entry in the connected hive list

svn path=/trunk/; revision=22684
This commit is contained in:
Art Yerkes 2006-06-29 03:48:43 +00:00
parent c6661f1f9e
commit 61cb74d018
4 changed files with 143 additions and 171 deletions

View file

@ -358,6 +358,9 @@ typedef struct _KEY_OBJECT
/* Time stamp for the last access by the parse routine */ /* Time stamp for the last access by the parse routine */
ULONG TimeStamp; ULONG TimeStamp;
/* List entry for connected hives */
LIST_ENTRY HiveList;
} KEY_OBJECT, *PKEY_OBJECT; } KEY_OBJECT, *PKEY_OBJECT;
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */ /* Bits 31-22 (top 10 bits) of the cell index is the directory index */

View file

@ -143,6 +143,8 @@ CmImportBinaryHive (PCHAR ChunkBase,
KeEnterCriticalRegion(); KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE); ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
DPRINT1("Adding new hive\n");
/* Add the new hive to the hive list */ /* Add the new hive to the hive list */
InsertTailList(&CmiHiveListHead, &Hive->HiveList); InsertTailList(&CmiHiveListHead, &Hive->HiveList);
@ -195,7 +197,6 @@ CmImportSystemHive(PCHAR ChunkBase,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1 ("CmiConnectHive(%wZ) failed (Status %lx)\n", &KeyName, Status); DPRINT1 ("CmiConnectHive(%wZ) failed (Status %lx)\n", &KeyName, Status);
// CmiRemoveRegistryHive(RegistryHive);
return FALSE; return FALSE;
} }

View file

@ -36,6 +36,7 @@ ERESOURCE CmiRegistryLock;
KTIMER CmiWorkerTimer; KTIMER CmiWorkerTimer;
LIST_ENTRY CmiKeyObjectListHead; LIST_ENTRY CmiKeyObjectListHead;
LIST_ENTRY CmiConnectedHiveList;
ULONG CmiTimer = 0; ULONG CmiTimer = 0;
volatile BOOLEAN CmiHiveSyncEnabled = FALSE; volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
@ -385,6 +386,7 @@ CmInitializeRegistry(VOID)
/* Initialize the key object list */ /* Initialize the key object list */
InitializeListHead(&CmiKeyObjectListHead); InitializeListHead(&CmiKeyObjectListHead);
InitializeListHead(&CmiConnectedHiveList);
/* Initialize the worker timer */ /* Initialize the worker timer */
KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer); KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
@ -694,7 +696,6 @@ CmiCreateCurrentControlSetLink(VOID)
return Status; return Status;
} }
NTSTATUS NTSTATUS
CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
IN PREGISTRY_HIVE RegistryHive) IN PREGISTRY_HIVE RegistryHive)
@ -717,6 +718,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
FALSE, FALSE,
&ObjectCreateInfo, &ObjectCreateInfo,
&ObjectName); &ObjectName);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status); DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
@ -730,7 +732,9 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
CmiKeyType, CmiKeyType,
NULL, NULL,
NULL); NULL);
/* Yields a new reference */
ObpReleaseCapturedAttributes(&ObjectCreateInfo); ObpReleaseCapturedAttributes(&ObjectCreateInfo);
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName); if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
@ -787,30 +791,15 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
0, 0,
NULL, NULL,
NULL); NULL);
DPRINT("Status %x\n", Status); DPRINT("Status %x\n", Status);
NewKey->RegistryHive = RegistryHive; NewKey->RegistryHive = RegistryHive;
NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset; NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL); NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
NewKey->Flags = 0; NewKey->Flags = 0;
NewKey->NumberOfSubKeys = 0; NewKey->NumberOfSubKeys = 0;
InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
if (NewKey->KeyCell->NumberOfSubKeys != 0)
{
NewKey->SubKeys = ExAllocatePool(NonPagedPool,
NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
if (NewKey->SubKeys == NULL)
{
DPRINT("ExAllocatePool() failed\n");
ObDereferenceObject (NewKey);
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
NewKey->SubKeys = NULL; NewKey->SubKeys = NULL;
} InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
InsertTailList(&CmiConnectedHiveList, &NewKey->HiveList);
DPRINT ("SubName %S\n", SubName); DPRINT ("SubName %S\n", SubName);
@ -830,10 +819,11 @@ DPRINT("Status %x\n", Status);
} }
CmiAddKeyToList (ParentKey, NewKey); CmiAddKeyToList (ParentKey, NewKey);
ObDereferenceObject (ParentKey);
VERIFY_KEY_OBJECT(NewKey); VERIFY_KEY_OBJECT(NewKey);
/* We're holding a pointer to the parent key .. We must keep it
* referenced */
/* Note: Do not dereference NewKey here! */ /* Note: Do not dereference NewKey here! */
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -845,9 +835,8 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
OUT PREGISTRY_HIVE *RegistryHive) OUT PREGISTRY_HIVE *RegistryHive)
{ {
PKEY_OBJECT KeyObject; PKEY_OBJECT KeyObject;
PREGISTRY_HIVE Hive;
HANDLE KeyHandle; HANDLE KeyHandle;
NTSTATUS Status; NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
PLIST_ENTRY CurrentEntry; PLIST_ENTRY CurrentEntry;
PKEY_OBJECT CurrentKey; PKEY_OBJECT CurrentKey;
@ -875,6 +864,7 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
(PVOID*)&KeyObject, (PVOID*)&KeyObject,
NULL); NULL);
ZwClose (KeyHandle); ZwClose (KeyHandle);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status); DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
@ -882,61 +872,39 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
} }
DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive); DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
{
DPRINT1 ("Key is not the Hive-Root-Key\n");
ObDereferenceObject (KeyObject);
return STATUS_INVALID_PARAMETER;
}
/* Acquire registry lock exclusively */ /* Acquire registry lock exclusively */
KeEnterCriticalRegion(); KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE); ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
CurrentEntry = CmiKeyObjectListHead.Flink; /* Find out if we represent a connected hive. */
while (CurrentEntry != &CmiKeyObjectListHead) for( CurrentEntry = CmiConnectedHiveList.Flink;
{ CurrentEntry != &CmiConnectedHiveList;
CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry); CurrentEntry = CurrentEntry->Flink ) {
if (1 == ObGetObjectPointerCount(CurrentKey) && CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, HiveList);
!(CurrentKey->Flags & KO_MARKED_FOR_DELETE)) if( CurrentKey == KeyObject ) {
{ /* Remove the connected hive from the connected hive list */
ObDereferenceObject(CurrentKey); RemoveEntryList(CurrentEntry);
CurrentEntry = CmiKeyObjectListHead.Flink; /* found ourselves in the connected hive list */
} *RegistryHive = KeyObject->RegistryHive;
else Status = STATUS_SUCCESS;
{
CurrentEntry = CurrentEntry->Flink;
}
}
if (ObGetObjectHandleCount (KeyObject) != 0 || /* Release references captured in CmiConnectHive */
ObGetObjectPointerCount (KeyObject) != 2) ObDereferenceObject (KeyObject->ParentKey);
{
DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
ObDereferenceObject (KeyObject); ObDereferenceObject (KeyObject);
break;
}
}
/* Release registry lock */ /* Release registry lock */
ExReleaseResourceLite (&CmiRegistryLock); ExReleaseResourceLite (&CmiRegistryLock);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
return STATUS_UNSUCCESSFUL; /* Release reference above */
}
Hive = KeyObject->RegistryHive;
/* Dereference KeyObject twice to delete it */
ObDereferenceObject (KeyObject); ObDereferenceObject (KeyObject);
ObDereferenceObject (KeyObject);
*RegistryHive = Hive;
/* Release registry lock */
ExReleaseResourceLite (&CmiRegistryLock);
KeLeaveCriticalRegion();
DPRINT ("CmiDisconnectHive() done\n"); DPRINT ("CmiDisconnectHive() done\n");
return STATUS_SUCCESS; return Status;
} }

View file

@ -462,7 +462,7 @@ CmiObjectParse(IN PVOID ParsedObject,
ExReleaseResourceLite(&CmiRegistryLock); ExReleaseResourceLite(&CmiRegistryLock);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
DPRINT("CmiObjectParse: %s\n", FoundObject->Name); //DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
*Path = EndPtr; *Path = EndPtr;
@ -492,9 +492,9 @@ CmiObjectDelete(PVOID DeletedObject)
KeEnterCriticalRegion(); KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE); ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
//if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject))) if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
{ {
// DPRINT1("Key not found in parent list ???\n"); DPRINT1("Key not found in parent list ???\n");
} }
RemoveEntryList(&KeyObject->ListEntry); RemoveEntryList(&KeyObject->ListEntry);
@ -526,7 +526,7 @@ CmiObjectDelete(PVOID DeletedObject)
if (KeyObject->NumberOfSubKeys) if (KeyObject->NumberOfSubKeys)
{ {
//KEBUGCHECK(REGISTRY_ERROR); KEBUGCHECK(REGISTRY_ERROR);
} }
if (KeyObject->SizeOfSubKeys) if (KeyObject->SizeOfSubKeys)