[NTOS:IO]

- Properly parse SymbolicLinkName (in particular, don't assume it's null-terminated) in IoSetDeviceInterface. Fixes IoDeviceInterface test failures and subsequent crashes due to memory corruption
CORE-9456

svn path=/trunk/; revision=69729
This commit is contained in:
Thomas Faber 2015-10-28 10:59:59 +00:00
parent a644d30ee7
commit f3e8d3e967

View file

@ -16,6 +16,11 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* FIXME: This should be somewhere global instead of having 20 different versions */
#define GUID_STRING_CHARS 38
#define GUID_STRING_BYTES (GUID_STRING_CHARS * sizeof(WCHAR))
C_ASSERT(sizeof(L"{01234567-89ab-cdef-0123-456789abcdef}") == GUID_STRING_BYTES + sizeof(UNICODE_NULL));
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
PDEVICE_OBJECT PDEVICE_OBJECT
@ -1312,8 +1317,6 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
{ {
PDEVICE_OBJECT PhysicalDeviceObject; PDEVICE_OBJECT PhysicalDeviceObject;
UNICODE_STRING GuidString; UNICODE_STRING GuidString;
PWCHAR StartPosition;
PWCHAR EndPosition;
NTSTATUS Status; NTSTATUS Status;
LPCGUID EventGuid; LPCGUID EventGuid;
HANDLE InstanceHandle, ControlHandle; HANDLE InstanceHandle, ControlHandle;
@ -1321,25 +1324,64 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
ULONG LinkedValue, Index; ULONG LinkedValue, Index;
GUID DeviceGuid; GUID DeviceGuid;
UNICODE_STRING DosDevicesPrefix1 = RTL_CONSTANT_STRING(L"\\??\\");
UNICODE_STRING DosDevicesPrefix2 = RTL_CONSTANT_STRING(L"\\\\?\\");
UNICODE_STRING LinkNameNoPrefix;
USHORT i;
USHORT ReferenceStringOffset;
if (SymbolicLinkName == NULL) if (SymbolicLinkName == NULL)
return STATUS_INVALID_PARAMETER_1; {
return STATUS_INVALID_PARAMETER;
}
DPRINT("IoSetDeviceInterfaceState('%wZ', %u)\n", SymbolicLinkName, Enable); DPRINT("IoSetDeviceInterfaceState('%wZ', %u)\n", SymbolicLinkName, Enable);
/* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */ /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */
/* Get GUID from SymbolicLinkName */ /* Make sure it starts with the expected prefix */
StartPosition = wcschr(SymbolicLinkName->Buffer, L'{'); if (!RtlPrefixUnicodeString(&DosDevicesPrefix1, SymbolicLinkName, FALSE) &&
EndPosition = wcschr(SymbolicLinkName->Buffer, L'}'); !RtlPrefixUnicodeString(&DosDevicesPrefix2, SymbolicLinkName, FALSE))
if (!StartPosition ||!EndPosition || StartPosition > EndPosition)
{ {
DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n"); DPRINT1("IoSetDeviceInterfaceState() invalid link name '%wZ'\n", SymbolicLinkName);
return STATUS_INVALID_PARAMETER_1; return STATUS_INVALID_PARAMETER;
} }
GuidString.Buffer = StartPosition;
GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition);
/* Make a version without the prefix for further processing */
ASSERT(DosDevicesPrefix1.Length == DosDevicesPrefix2.Length);
ASSERT(SymbolicLinkName->Length >= DosDevicesPrefix1.Length);
LinkNameNoPrefix.Buffer = SymbolicLinkName->Buffer + DosDevicesPrefix1.Length / sizeof(WCHAR);
LinkNameNoPrefix.Length = SymbolicLinkName->Length - DosDevicesPrefix1.Length;
LinkNameNoPrefix.MaximumLength = LinkNameNoPrefix.Length;
/* Find the reference string, if any */
for (i = 0; i < LinkNameNoPrefix.Length / sizeof(WCHAR); i++)
{
if (LinkNameNoPrefix.Buffer[i] == L'\\')
{
break;
}
}
ReferenceStringOffset = i * sizeof(WCHAR);
/* The GUID is before the reference string or at the end */
ASSERT(LinkNameNoPrefix.Length >= ReferenceStringOffset);
if (ReferenceStringOffset < GUID_STRING_BYTES + sizeof(WCHAR))
{
DPRINT1("IoSetDeviceInterfaceState() invalid link name '%wZ'\n", SymbolicLinkName);
return STATUS_INVALID_PARAMETER;
}
GuidString.Buffer = LinkNameNoPrefix.Buffer + (ReferenceStringOffset - GUID_STRING_BYTES) / sizeof(WCHAR);
GuidString.Length = GUID_STRING_BYTES;
GuidString.MaximumLength = GuidString.Length;
Status = RtlGUIDFromString(&GuidString, &DeviceGuid);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlGUIDFromString() invalid GUID '%wZ' in link name '%wZ'\n", &GuidString, SymbolicLinkName);
return Status;
}
/* Open registry keys */
Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName, Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName,
KEY_CREATE_SUB_KEY, KEY_CREATE_SUB_KEY,
NULL, NULL,
@ -1384,16 +1426,28 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
return Status; return Status;
} }
DeviceInstance.Buffer = ExAllocatePool(PagedPool, (ULONG_PTR)StartPosition - (ULONG_PTR)SymbolicLinkName->Buffer); ASSERT(GuidString.Buffer >= LinkNameNoPrefix.Buffer + 1);
DeviceInstance.Length = (GuidString.Buffer - LinkNameNoPrefix.Buffer - 1) * sizeof(WCHAR);
if (DeviceInstance.Length == 0)
{
DPRINT1("No device instance in link name '%wZ'\n", SymbolicLinkName);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
DeviceInstance.MaximumLength = DeviceInstance.Length;
DeviceInstance.Buffer = ExAllocatePoolWithTag(PagedPool,
DeviceInstance.MaximumLength,
TAG_IO);
if (DeviceInstance.Buffer == NULL) if (DeviceInstance.Buffer == NULL)
{ {
/* no memory */ /* no memory */
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
DeviceInstance.MaximumLength = DeviceInstance.Length = ((ULONG_PTR)StartPosition - (ULONG_PTR)SymbolicLinkName->Buffer) - 5 * sizeof(WCHAR); RtlCopyMemory(DeviceInstance.Buffer,
RtlCopyMemory(DeviceInstance.Buffer, &SymbolicLinkName->Buffer[4], DeviceInstance.Length); LinkNameNoPrefix.Buffer,
for(Index = 0; Index < DeviceInstance.Length / sizeof(WCHAR); Index++) DeviceInstance.Length);
for (Index = 0; Index < DeviceInstance.Length / sizeof(WCHAR); Index++)
{ {
if (DeviceInstance.Buffer[Index] == L'#') if (DeviceInstance.Buffer[Index] == L'#')
{ {
@ -1405,19 +1459,12 @@ IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName,
if (!PhysicalDeviceObject) if (!PhysicalDeviceObject)
{ {
DPRINT1("IopGetDeviceObjectFromDeviceInstance failed to find status %wZ\n", &DeviceInstance); DPRINT1("IopGetDeviceObjectFromDeviceInstance failed to find device object for %wZ\n", &DeviceInstance);
ExFreePool(DeviceInstance.Buffer); ExFreePoolWithTag(DeviceInstance.Buffer, TAG_IO);
return STATUS_NOT_FOUND; return STATUS_OBJECT_NAME_NOT_FOUND;
} }
ExFreePool(DeviceInstance.Buffer); ExFreePoolWithTag(DeviceInstance.Buffer, TAG_IO);
Status = RtlGUIDFromString(&GuidString, &DeviceGuid);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlGUIDFromString() failed with status 0x%08lx\n", Status);
ObDereferenceObject(PhysicalDeviceObject);
return Status;
}
EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL; EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL;
IopNotifyPlugPlayNotification( IopNotifyPlugPlayNotification(