Use UNICODE_STRING and Rtl functions instead of LPWSTR variables (can prevent some buffer overflows)

Remove assumption that UNICODE_STRING buffers are always NULL terminated
Remove some intermediate buffers
Do not define multiple times PnP parent key

svn path=/trunk/; revision=31467
This commit is contained in:
Hervé Poussineau 2007-12-27 19:02:32 +00:00
parent fe052d8d46
commit 0edb8fe2f9

View file

@ -19,6 +19,8 @@
/* GLOBALS *******************************************************************/ /* GLOBALS *******************************************************************/
#define ENUM_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum"
PDEVICE_NODE IopRootDeviceNode; PDEVICE_NODE IopRootDeviceNode;
KSPIN_LOCK IopDeviceTreeLock; KSPIN_LOCK IopDeviceTreeLock;
ERESOURCE PpRegistryDeviceResource; ERESOURCE PpRegistryDeviceResource;
@ -403,12 +405,13 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
case DevicePropertyLocationInformation: case DevicePropertyLocationInformation:
case DevicePropertyUINumber: case DevicePropertyUINumber:
{ {
LPWSTR RegistryPropertyName, KeyNameBuffer; LPCWSTR RegistryPropertyName;
UNICODE_STRING KeyName, ValueName; UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
UNICODE_STRING ValueName;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
KEY_VALUE_PARTIAL_INFORMATION *ValueInformation; KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
ULONG ValueInformationLength; ULONG ValueInformationLength;
HANDLE KeyHandle; HANDLE hEnum, KeyHandle;
NTSTATUS Status; NTSTATUS Status;
switch (DeviceProperty) switch (DeviceProperty)
@ -434,56 +437,64 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
case DevicePropertyUINumber: case DevicePropertyUINumber:
RegistryPropertyName = L"UINumber"; break; RegistryPropertyName = L"UINumber"; break;
default: default:
RegistryPropertyName = NULL; break; /* Should not happen */
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
} }
KeyNameBuffer = ExAllocatePool(PagedPool, DPRINT("Registry property %S\n", RegistryPropertyName);
(49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
DPRINT("KeyNameBuffer: 0x%p, value %S\n", KeyNameBuffer, RegistryPropertyName); /* Open Enum key */
InitializeObjectAttributes(&ObjectAttributes, &EnumU,
if (KeyNameBuffer == NULL) OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
return STATUS_INSUFFICIENT_RESOURCES; Status = ZwOpenKey(&hEnum, 0, &ObjectAttributes);
wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
wcscat(KeyNameBuffer, DeviceNode->InstancePath.Buffer);
RtlInitUnicodeString(&KeyName, KeyNameBuffer);
InitializeObjectAttributes(&ObjectAttributes, &KeyName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
ExFreePool(KeyNameBuffer);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
return Status; return Status;
RtlInitUnicodeString(&ValueName, RegistryPropertyName); /* Open instance key */
InitializeObjectAttributes(&ObjectAttributes, &DeviceNode->InstancePath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hEnum, NULL);
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
ZwClose(hEnum);
if (!NT_SUCCESS(Status))
return Status;
/* Allocate buffer to read as much data as required by the caller */
ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
Data[0]) + BufferLength; Data[0]) + BufferLength;
ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength); ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
if (ValueInformation == NULL) if (!ValueInformation)
{ {
ZwClose(KeyHandle); ZwClose(KeyHandle);
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
/* Read the value */
RtlInitUnicodeString(&ValueName, RegistryPropertyName);
Status = ZwQueryValueKey(KeyHandle, &ValueName, Status = ZwQueryValueKey(KeyHandle, &ValueName,
KeyValuePartialInformation, ValueInformation, KeyValuePartialInformation, ValueInformation,
ValueInformationLength, ValueInformationLength,
&ValueInformationLength); &ValueInformationLength);
*ResultLength = ValueInformation->DataLength;
ZwClose(KeyHandle); ZwClose(KeyHandle);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
ExFreePool(ValueInformation); ExFreePool(ValueInformation);
if (Status == STATUS_BUFFER_OVERFLOW) if (Status == STATUS_BUFFER_OVERFLOW)
{
*ResultLength = ValueInformation->DataLength;
return STATUS_BUFFER_TOO_SMALL; return STATUS_BUFFER_TOO_SMALL;
}
else else
{
*ResultLength = 0;
return Status; return Status;
} }
}
/* Return data */
*ResultLength = ValueInformation->DataLength;
/* FIXME: Verify the value (NULL-terminated, correct format). */ /* FIXME: Verify the value (NULL-terminated, correct format). */
RtlCopyMemory(PropertyBuffer, ValueInformation->Data, RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
ValueInformation->DataLength); ValueInformation->DataLength);
ExFreePool(ValueInformation); ExFreePool(ValueInformation);
@ -511,21 +522,17 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
break; break;
case DevicePropertyEnumeratorName: case DevicePropertyEnumeratorName:
/* A buffer overflow can't happen here, since InstancePath
* always contains the enumerator name followed by \\ */
Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\'); Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
if (Ptr != NULL) ASSERT(Ptr);
{ Length = (Ptr - DeviceNode->InstancePath.Buffer + 1) * sizeof(WCHAR);
Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR);
Data = DeviceNode->InstancePath.Buffer; Data = DeviceNode->InstancePath.Buffer;
}
else
{
Length = 0;
Data = NULL;
}
break; break;
case DevicePropertyPhysicalDeviceObjectName: case DevicePropertyPhysicalDeviceObjectName:
Length = DeviceNode->InstancePath.Length + sizeof(WCHAR); /* InstancePath buffer is NULL terminated, so we can do this */
Length = DeviceNode->InstancePath.MaximumLength;
Data = DeviceNode->InstancePath.Buffer; Data = DeviceNode->InstancePath.Buffer;
break; break;
@ -533,18 +540,15 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
return STATUS_INVALID_PARAMETER_2; return STATUS_INVALID_PARAMETER_2;
} }
/* Prepare returned values */
*ResultLength = Length; *ResultLength = Length;
if (BufferLength < Length) if (BufferLength < Length)
return STATUS_BUFFER_TOO_SMALL; return STATUS_BUFFER_TOO_SMALL;
RtlCopyMemory(PropertyBuffer, Data, Length); RtlCopyMemory(PropertyBuffer, Data, Length);
/* Terminate the string */ /* NULL terminate the string (if required) */
if (DeviceProperty == DevicePropertyEnumeratorName if (DeviceProperty == DevicePropertyEnumeratorName)
|| DeviceProperty == DevicePropertyPhysicalDeviceObjectName) ((LPWSTR)PropertyBuffer)[Length / sizeof(WCHAR)] = UNICODE_NULL;
{
Ptr = (PWSTR)PropertyBuffer;
Ptr[(Length / sizeof(WCHAR)) - 1] = 0;
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1062,79 +1066,107 @@ IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
} }
static /*
* IopCreateDeviceKeyPath
*
* Creates a registry key
*
* Parameters
* RegistryPath
* Name of the key to be created.
* Handle
* Handle to the newly created key
*
* Remarks
* This method can create nested trees, so parent of RegistryPath can
* be not existant, and will be created if needed.
*/
NTSTATUS NTSTATUS
IopCreateDeviceKeyPath(PWSTR Path, NTAPI
PHANDLE Handle) IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
OUT PHANDLE Handle)
{ {
UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
HANDLE hParent = NULL, hKey;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR KeyBuffer[MAX_PATH];
UNICODE_STRING KeyName; UNICODE_STRING KeyName;
HANDLE KeyHandle; LPCWSTR Current, Last;
ULONG dwLength;
NTSTATUS Status; NTSTATUS Status;
PWCHAR Current;
PWCHAR Next;
/* Assume failure */
*Handle = NULL; *Handle = NULL;
if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0) /* Open root key for device instances */
{ InitializeObjectAttributes(&ObjectAttributes,
return STATUS_INVALID_PARAMETER; &EnumU,
}
wcsncpy (KeyBuffer, Path, MAX_PATH-1);
/* Skip \\Registry\\ */
Current = KeyBuffer;
Current = wcschr (Current, L'\\') + 1;
Current = wcschr (Current, L'\\') + 1;
while (TRUE)
{
Next = wcschr (Current, L'\\');
if (Next == NULL)
{
/* The end */
}
else
{
*Next = 0;
}
RtlInitUnicodeString (&KeyName, KeyBuffer);
InitializeObjectAttributes (&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE, OBJ_CASE_INSENSITIVE,
NULL, NULL,
NULL); NULL);
Status = ZwOpenKey(&hParent,
KEY_CREATE_SUB_KEY,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
return Status;
}
DPRINT("Create '%S'\n", KeyName.Buffer); Current = KeyName.Buffer = RegistryPath->Buffer;
Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
Status = ZwCreateKey (&KeyHandle, /* Go up to the end of the string */
KEY_ALL_ACCESS, while (Current <= Last)
{
if (Current != Last && *Current != '\\')
{
/* Not the end of the string and not a separator */
Current++;
continue;
}
/* Prepare relative key name */
dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
KeyName.MaximumLength = KeyName.Length = dwLength;
DPRINT("Create '%wZ'\n", &KeyName);
/* Open key */
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
hParent,
NULL);
Status = ZwCreateKey(&hKey,
Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
&ObjectAttributes, &ObjectAttributes,
0, 0,
NULL, NULL,
0, 0,
NULL); NULL);
if (!NT_SUCCESS (Status))
/* Close parent key handle, we don't need it anymore */
if (hParent)
ZwClose(hParent);
/* Key opening/creating failed? */
if (!NT_SUCCESS(Status))
{ {
DPRINT ("ZwCreateKey() failed with status %x\n", Status); DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
return Status; return Status;
} }
if (Next == NULL) /* Check if it is the end of the string */
if (Current == Last)
{ {
*Handle = KeyHandle; /* Yes, return success */
*Handle = hKey;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
else
{
ZwClose (KeyHandle);
*Next = L'\\';
}
Current = Next + 1; /* Start with this new parent key */
hParent = hKey;
Current++;
KeyName.Buffer = (LPWSTR)Current;
} }
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
@ -1225,41 +1257,6 @@ IopSetDeviceInstanceData(HANDLE InstanceKey,
sizeof(DefaultConfigFlags)); sizeof(DefaultConfigFlags));
} }
#if 0
if (DeviceNode->PhysicalDeviceObject != NULL)
{
/* Create the 'Control' key */
RtlInitUnicodeString(&KeyName,
L"Control");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
InstanceKey,
NULL);
Status = ZwCreateKey(&LogConfKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (NT_SUCCESS(Status))
{
ULONG Reference = (ULONG)DeviceNode->PhysicalDeviceObject;
RtlInitUnicodeString(&KeyName,
L"DeviceReference");
Status = ZwSetValueKey(LogConfKey,
&KeyName,
0,
REG_DWORD,
&Reference,
sizeof(PVOID));
ZwClose(LogConfKey);
}
}
#endif
DPRINT("IopSetDeviceInstanceData() done\n"); DPRINT("IopSetDeviceInstanceData() done\n");
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -1606,78 +1603,76 @@ NTSTATUS
IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
PUNICODE_STRING ParentIdPrefix) PUNICODE_STRING ParentIdPrefix)
{ {
ULONG KeyNameBufferLength; ULONG BufferLength;
PWSTR KeyNameBuffer = NULL; UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL; PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation;
UNICODE_STRING KeyName;
UNICODE_STRING KeyValue; UNICODE_STRING KeyValue;
UNICODE_STRING ValueName; UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"ParentIdPrefix");
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hKey = NULL; HANDLE hEnum, hKey = NULL;
ULONG crc32; ULONG crc32;
NTSTATUS Status; NTSTATUS Status;
/* HACK: As long as some devices have a NULL device /* Allocate a buffer big enough to read a MAX_PATH prefix */
* instance path, the following test is required :( BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
*/ ParentIdPrefixInformation = ExAllocatePool(PagedPool, BufferLength + sizeof(WCHAR));
if (DeviceNode->Parent->InstancePath.Length == 0)
{
DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
&DeviceNode->InstancePath);
return STATUS_UNSUCCESSFUL;
}
/* 1. Try to retrieve ParentIdPrefix from registry */ /* Check if allocation succeeded */
KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
if (!ParentIdPrefixInformation) if (!ParentIdPrefixInformation)
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_NO_MEMORY;
goto cleanup; goto cleanup;
} }
KeyNameBuffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
if (!KeyNameBuffer) /* Open enum key */
{ InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = STATUS_INSUFFICIENT_RESOURCES; Status = ZwOpenKey(&hEnum, 0, &ObjectAttributes);
goto cleanup;
}
wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
wcscat(KeyNameBuffer, DeviceNode->Parent->InstancePath.Buffer);
RtlInitUnicodeString(&KeyName, KeyNameBuffer);
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
goto cleanup; goto cleanup;
RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
/* Open instance key */
InitializeObjectAttributes(&ObjectAttributes, &DeviceNode->Parent->InstancePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hEnum, NULL);
Status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
ZwClose(hEnum);
if (!NT_SUCCESS(Status))
goto cleanup;
/* Read the prefix */
Status = ZwQueryValueKey( Status = ZwQueryValueKey(
hKey, &ValueName, hKey, &ValueName,
KeyValuePartialInformation, ParentIdPrefixInformation, KeyValuePartialInformation, ParentIdPrefixInformation,
KeyNameBufferLength, &KeyNameBufferLength); BufferLength, &BufferLength);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Yes, we read something */
if (ParentIdPrefixInformation->Type != REG_SZ) if (ParentIdPrefixInformation->Type != REG_SZ)
/* Hm, it was of the wrong type. Fail */
Status = STATUS_UNSUCCESSFUL; Status = STATUS_UNSUCCESSFUL;
else else
{ {
/* OK, value is correct ; prepare to return it */
KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength; KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data; KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
} }
goto cleanup;
} /* We're done */
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
{
KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
goto cleanup; goto cleanup;
} }
/* 2. Create the ParentIdPrefix value */ /* Check if we failed due to value not calculated */
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
/* Another reason, fail */
goto cleanup;
/* Compute the prefix string of the parent */
crc32 = RtlComputeCrc32(0, crc32 = RtlComputeCrc32(0,
(PUCHAR)DeviceNode->Parent->InstancePath.Buffer, (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
DeviceNode->Parent->InstancePath.Length); DeviceNode->Parent->InstancePath.Length);
swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32); /* Prepare the value to return */
RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data); /* (yes, it's safe to reuse ParentIdPrefixInformation buffer, which is at least MAX_PATH WCHARs long */
swprintf((PWSTR)ParentIdPrefixInformation, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
/* 3. Try to write the ParentIdPrefix to registry */ /* 3. Try to write the ParentIdPrefix to registry */
Status = ZwSetValueKey(hKey, Status = ZwSetValueKey(hKey,
@ -1685,7 +1680,7 @@ IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
0, 0,
REG_SZ, REG_SZ,
(PVOID)KeyValue.Buffer, (PVOID)KeyValue.Buffer,
(wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR)); KeyValue.MaximumLength);
cleanup: cleanup:
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
@ -1693,8 +1688,8 @@ cleanup:
/* Duplicate the string to return it */ /* Duplicate the string to return it */
Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix); Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
} }
/* General cleanup */
ExFreePool(ParentIdPrefixInformation); ExFreePool(ParentIdPrefixInformation);
ExFreePool(KeyNameBuffer);
if (hKey != NULL) if (hKey != NULL)
ZwClose(hKey); ZwClose(hKey);
return Status; return Status;
@ -1727,9 +1722,9 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
PDEVICE_NODE ParentDeviceNode; PDEVICE_NODE ParentDeviceNode;
WCHAR InstancePath[MAX_PATH]; WCHAR InstancePath[MAX_PATH];
UNICODE_STRING InstancePathU = { 0, sizeof(InstancePath), InstancePath };
IO_STACK_LOCATION Stack; IO_STACK_LOCATION Stack;
NTSTATUS Status; NTSTATUS Status;
PWSTR KeyBuffer;
PWSTR Ptr; PWSTR Ptr;
USHORT Length; USHORT Length;
USHORT TotalLength; USHORT TotalLength;
@ -1791,12 +1786,7 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Copy the device id string */ /* Copy the device id string */
wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information); RtlAppendUnicodeToString(&InstancePathU, (PWSTR)IoStatusBlock.Information);
/*
* FIXME: Check for valid characters, if there is invalid characters
* then bugcheck.
*/
} }
else else
{ {
@ -1834,21 +1824,16 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Append the instance id string */ /* Append the instance id string */
wcscat(InstancePath, L"\\"); RtlAppendUnicodeToString(&InstancePathU, L"\\");
if (ParentIdPrefix.Length > 0) if (ParentIdPrefix.Length > 0)
{ {
/* Add information from parent bus device to InstancePath */ /* Add information from parent bus device to InstancePath */
wcscat(InstancePath, ParentIdPrefix.Buffer); RtlAppendUnicodeStringToString(&InstancePathU, &ParentIdPrefix);
if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information) if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
wcscat(InstancePath, L"&"); RtlAppendUnicodeToString(&InstancePathU, L"&");
} }
if (IoStatusBlock.Information) if (IoStatusBlock.Information)
wcscat(InstancePath, (PWSTR)IoStatusBlock.Information); RtlAppendUnicodeToString(&InstancePathU, (PWSTR)IoStatusBlock.Information);
/*
* FIXME: Check for valid characters, if there is invalid characters
* then bugcheck
*/
} }
else else
{ {
@ -1856,29 +1841,25 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
} }
RtlFreeUnicodeString(&ParentIdPrefix); RtlFreeUnicodeString(&ParentIdPrefix);
if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath)) /*
* FIXME: Check for valid characters, if there is invalid characters
* then bugcheck.
*/
Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&InstancePathU, &DeviceNode->InstancePath);
if (!NT_SUCCESS(Status))
{ {
DPRINT("No resources\n"); DPRINT("No resources\n");
/* FIXME: Cleanup and disable device */ /* FIXME: Cleanup and disable device */
} }
DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); DPRINT("InstancePath is %wZ\n", &DeviceNode->InstancePath);
/* /* Create registry key for the instance id, if it doesn't exist yet */
* Create registry key for the instance id, if it doesn't exist yet Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceKey);
*/
KeyBuffer = ExAllocatePool(
PagedPool,
(49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
Status = IopCreateDeviceKeyPath(KeyBuffer, &InstanceKey);
ExFreePool(KeyBuffer);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ DPRINT1("IopCreateDeviceKeyPath('%wZ') failed (Status 0x%08lx)\n", &DeviceNode->InstancePath, Status);
DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
}
{ {
/* Set 'Capabilities' value */ /* Set 'Capabilities' value */
@ -2329,7 +2310,7 @@ NTSTATUS
IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
PVOID Context) PVOID Context)
{ {
RTL_QUERY_REGISTRY_TABLE QueryTable[3]; RTL_QUERY_REGISTRY_TABLE QueryTable[4];
PDEVICE_NODE ParentDeviceNode; PDEVICE_NODE ParentDeviceNode;
PUNICODE_STRING Service; PUNICODE_STRING Service;
UNICODE_STRING ClassGUID; UNICODE_STRING ClassGUID;
@ -2353,49 +2334,52 @@ IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
* Make sure this device node is a direct child of the parent device node * Make sure this device node is a direct child of the parent device node
* that is given as an argument * that is given as an argument
*/ */
if (DeviceNode->Parent != ParentDeviceNode) ASSERT(DeviceNode->Parent == ParentDeviceNode);
{
/* Stop the traversal immediately and indicate successful operation */
DPRINT("Stop\n");
return STATUS_UNSUCCESSFUL;
}
if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
{ {
WCHAR RegKeyBuffer[MAX_PATH]; OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING RegKey; UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
HANDLE hEnum;
RegKey.Length = 0; /* Open Enum key */
RegKey.MaximumLength = sizeof(RegKeyBuffer); InitializeObjectAttributes(&ObjectAttributes, &EnumU,
RegKey.Buffer = RegKeyBuffer; OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL)
Status = ZwOpenKey(&hEnum, 0, &ObjectAttributes);
/* if (!NT_SUCCESS(Status))
* Retrieve configuration from Enum key {
*/ /* FIXME: Log the error */
IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
Service = &DeviceNode->ServiceName; return Status;
}
/* Prepare query table */
RtlZeroMemory(QueryTable, sizeof(QueryTable)); RtlZeroMemory(QueryTable, sizeof(QueryTable));
Service = &DeviceNode->ServiceName;
RtlInitUnicodeString(Service, NULL); RtlInitUnicodeString(Service, NULL);
RtlInitUnicodeString(&ClassGUID, NULL); RtlInitUnicodeString(&ClassGUID, NULL);
QueryTable[0].Name = L"Service"; /* Hopefully, this string is always NULL terminated */
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].Name = DeviceNode->InstancePath.Buffer;
QueryTable[0].EntryContext = Service; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
QueryTable[1].Name = L"ClassGUID"; QueryTable[1].Name = L"Service";
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[1].EntryContext = &ClassGUID; QueryTable[1].EntryContext = Service;
QueryTable[1].DefaultType = REG_SZ;
QueryTable[1].DefaultData = L"";
QueryTable[1].DefaultLength = 0;
RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); QueryTable[2].Name = L"ClassGUID";
RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
QueryTable[2].EntryContext = &ClassGUID;
QueryTable[2].DefaultType = REG_SZ;
QueryTable[2].DefaultData = L"";
QueryTable[2].DefaultLength = 0;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, /* Read registry */
RegKey.Buffer, QueryTable, NULL, NULL); Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR)hEnum,
QueryTable, NULL, NULL);
ZwClose(hEnum);
/* Check for an error */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* FIXME: Log the error */ /* FIXME: Log the error */
@ -2405,7 +2389,8 @@ IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
if (Service->Buffer == NULL) /* Check for a NULL service */
if (Service->Length == 0)
{ {
IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
@ -2421,7 +2406,7 @@ IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
DPRINT("Got Service %S\n", Service->Buffer); DPRINT("Got Service %wZ\n", Service);
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -2476,16 +2461,7 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
* Make sure this device node is a direct child of the parent device node * Make sure this device node is a direct child of the parent device node
* that is given as an argument * that is given as an argument
*/ */
#if 0 ASSERT(DeviceNode->Parent == ParentDeviceNode);
if (DeviceNode->Parent != ParentDeviceNode)
{
/*
* Stop the traversal immediately and indicate unsuccessful operation
*/
DPRINT("Stop\n");
return STATUS_UNSUCCESSFUL;
}
#endif
if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) && if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
!IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) && !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
@ -2563,8 +2539,8 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED); IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
/* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */ /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
CPRINT("Initialization of service %S failed (Status %x)\n", DPRINT("Initialization of service %wZ failed (Status %x)\n",
DeviceNode->ServiceName.Buffer, Status); &DeviceNode->ServiceName, Status);
} }
} }
} }