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,92 +696,94 @@ 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)
{ {
UNICODE_STRING RemainingPath; UNICODE_STRING RemainingPath;
PKEY_OBJECT ParentKey; PKEY_OBJECT ParentKey;
PKEY_OBJECT NewKey; PKEY_OBJECT NewKey;
NTSTATUS Status; NTSTATUS Status;
PWSTR SubName; PWSTR SubName;
UNICODE_STRING ObjectName; UNICODE_STRING ObjectName;
OBJECT_CREATE_INFORMATION ObjectCreateInfo; OBJECT_CREATE_INFORMATION ObjectCreateInfo;
DPRINT("CmiConnectHive(%p, %p) called.\n", DPRINT("CmiConnectHive(%p, %p) called.\n",
KeyObjectAttributes, RegistryHive); KeyObjectAttributes, RegistryHive);
/* Capture all the info */ /* Capture all the info */
DPRINT("Capturing Create Info\n"); DPRINT("Capturing Create Info\n");
Status = ObpCaptureObjectAttributes(KeyObjectAttributes, Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
KernelMode, KernelMode,
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);
return Status; return Status;
} }
Status = CmFindObject(&ObjectCreateInfo, Status = CmFindObject(&ObjectCreateInfo,
&ObjectName, &ObjectName,
(PVOID*)&ParentKey, (PVOID*)&ParentKey,
&RemainingPath, &RemainingPath,
CmiKeyType,
NULL,
NULL);
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
if (!NT_SUCCESS(Status))
{
return Status;
}
DPRINT ("RemainingPath %wZ\n", &RemainingPath);
if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
{
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return STATUS_OBJECT_NAME_COLLISION;
}
/* Ignore leading backslash */
SubName = RemainingPath.Buffer;
if (*SubName == L'\\')
SubName++;
/* If RemainingPath contains \ we must return error
because CmiConnectHive() can not create trees */
if (wcschr (SubName, L'\\') != NULL)
{
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
DPRINT("RemainingPath %wZ ParentKey %p\n",
&RemainingPath, ParentKey);
Status = ObCreateObject(KernelMode,
CmiKeyType, CmiKeyType,
NULL, NULL,
KernelMode, NULL);
NULL, /* Yields a new reference */
sizeof(KEY_OBJECT), ObpReleaseCapturedAttributes(&ObjectCreateInfo);
0,
0, if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
(PVOID*)&NewKey); if (!NT_SUCCESS(Status))
{
if (!NT_SUCCESS(Status)) return Status;
{ }
DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
ObDereferenceObject (ParentKey); DPRINT ("RemainingPath %wZ\n", &RemainingPath);
RtlFreeUnicodeString(&RemainingPath);
return Status; if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
} {
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return STATUS_OBJECT_NAME_COLLISION;
}
/* Ignore leading backslash */
SubName = RemainingPath.Buffer;
if (*SubName == L'\\')
SubName++;
/* If RemainingPath contains \ we must return error
because CmiConnectHive() can not create trees */
if (wcschr (SubName, L'\\') != NULL)
{
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
DPRINT("RemainingPath %wZ ParentKey %p\n",
&RemainingPath, ParentKey);
Status = ObCreateObject(KernelMode,
CmiKeyType,
NULL,
KernelMode,
NULL,
sizeof(KEY_OBJECT),
0,
0,
(PVOID*)&NewKey);
if (!NT_SUCCESS(Status))
{
DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
ObDereferenceObject (ParentKey);
RtlFreeUnicodeString(&RemainingPath);
return Status;
}
DPRINT("Inserting Key into Object Tree\n"); DPRINT("Inserting Key into Object Tree\n");
Status = ObInsertObject((PVOID)NewKey, Status = ObInsertObject((PVOID)NewKey,
NULL, NULL,
@ -787,56 +791,42 @@ 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); NewKey->SubKeys = NULL;
if (NewKey->KeyCell->NumberOfSubKeys != 0) InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
{ InsertTailList(&CmiConnectedHiveList, &NewKey->HiveList);
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;
}
DPRINT ("SubName %S\n", SubName); DPRINT ("SubName %S\n", SubName);
Status = RtlpCreateUnicodeString(&NewKey->Name, Status = RtlpCreateUnicodeString(&NewKey->Name,
SubName, NonPagedPool); SubName, NonPagedPool);
RtlFreeUnicodeString(&RemainingPath); RtlFreeUnicodeString(&RemainingPath);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status); DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
if (NewKey->SubKeys != NULL) if (NewKey->SubKeys != NULL)
{ {
ExFreePool (NewKey->SubKeys); ExFreePool (NewKey->SubKeys);
} }
ObDereferenceObject (NewKey); ObDereferenceObject (NewKey);
ObDereferenceObject (ParentKey); ObDereferenceObject (ParentKey);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
CmiAddKeyToList (ParentKey, NewKey); CmiAddKeyToList (ParentKey, NewKey);
ObDereferenceObject (ParentKey);
VERIFY_KEY_OBJECT(NewKey); VERIFY_KEY_OBJECT(NewKey);
/* Note: Do not dereference NewKey here! */ /* We're holding a pointer to the parent key .. We must keep it
* referenced */
/* 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; /* Release references captured in CmiConnectHive */
} ObDereferenceObject (KeyObject->ParentKey);
ObDereferenceObject (KeyObject);
break;
}
} }
if (ObGetObjectHandleCount (KeyObject) != 0 ||
ObGetObjectPointerCount (KeyObject) != 2)
{
DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
ObDereferenceObject (KeyObject);
/* Release registry lock */
ExReleaseResourceLite (&CmiRegistryLock);
KeLeaveCriticalRegion();
return STATUS_UNSUCCESSFUL;
}
Hive = KeyObject->RegistryHive;
/* Dereference KeyObject twice to delete it */
ObDereferenceObject (KeyObject);
ObDereferenceObject (KeyObject);
*RegistryHive = Hive;
/* Release registry lock */ /* Release registry lock */
ExReleaseResourceLite (&CmiRegistryLock); ExReleaseResourceLite (&CmiRegistryLock);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
/* Release reference above */
ObDereferenceObject (KeyObject);
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)