Author: tfaber Date: Wed Oct 28 10:59:59 2015 New Revision: 69729
URL: http://svn.reactos.org/svn/reactos?rev=69729&view=rev Log: [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
Modified: trunk/reactos/ntoskrnl/io/iomgr/deviface.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/deviface.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/deviface.... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/deviface.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/io/iomgr/deviface.c [iso-8859-1] Wed Oct 28 10:59:59 2015 @@ -15,6 +15,11 @@
#define NDEBUG #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 *****************************************************************/
@@ -1312,8 +1317,6 @@ { PDEVICE_OBJECT PhysicalDeviceObject; UNICODE_STRING GuidString; - PWCHAR StartPosition; - PWCHAR EndPosition; NTSTATUS Status; LPCGUID EventGuid; HANDLE InstanceHandle, ControlHandle; @@ -1321,25 +1324,64 @@ OBJECT_ATTRIBUTES ObjectAttributes; ULONG LinkedValue, Index; 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) - return STATUS_INVALID_PARAMETER_1; + { + return STATUS_INVALID_PARAMETER; + }
DPRINT("IoSetDeviceInterfaceState('%wZ', %u)\n", SymbolicLinkName, Enable);
/* Symbolic link name is ??\ACPI#PNP0501#1#{GUID}\ReferenceString */ - /* Get GUID from SymbolicLinkName */ - StartPosition = wcschr(SymbolicLinkName->Buffer, L'{'); - EndPosition = wcschr(SymbolicLinkName->Buffer, L'}'); - if (!StartPosition ||!EndPosition || StartPosition > EndPosition) - { - DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n"); - return STATUS_INVALID_PARAMETER_1; - } - GuidString.Buffer = StartPosition; - GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition); - + /* Make sure it starts with the expected prefix */ + if (!RtlPrefixUnicodeString(&DosDevicesPrefix1, SymbolicLinkName, FALSE) && + !RtlPrefixUnicodeString(&DosDevicesPrefix2, SymbolicLinkName, FALSE)) + { + DPRINT1("IoSetDeviceInterfaceState() invalid link name '%wZ'\n", SymbolicLinkName); + return STATUS_INVALID_PARAMETER; + } + + /* 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, KEY_CREATE_SUB_KEY, NULL, @@ -1384,16 +1426,28 @@ 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) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; }
- DeviceInstance.MaximumLength = DeviceInstance.Length = ((ULONG_PTR)StartPosition - (ULONG_PTR)SymbolicLinkName->Buffer) - 5 * sizeof(WCHAR); - RtlCopyMemory(DeviceInstance.Buffer, &SymbolicLinkName->Buffer[4], DeviceInstance.Length); - for(Index = 0; Index < DeviceInstance.Length / sizeof(WCHAR); Index++) + RtlCopyMemory(DeviceInstance.Buffer, + LinkNameNoPrefix.Buffer, + DeviceInstance.Length); + + for (Index = 0; Index < DeviceInstance.Length / sizeof(WCHAR); Index++) { if (DeviceInstance.Buffer[Index] == L'#') { @@ -1402,22 +1456,15 @@ }
PhysicalDeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); - + if (!PhysicalDeviceObject) { - DPRINT1("IopGetDeviceObjectFromDeviceInstance failed to find status %wZ\n", &DeviceInstance); - ExFreePool(DeviceInstance.Buffer); - return STATUS_NOT_FOUND; - } - - ExFreePool(DeviceInstance.Buffer); - Status = RtlGUIDFromString(&GuidString, &DeviceGuid); - if (!NT_SUCCESS(Status)) - { - DPRINT1("RtlGUIDFromString() failed with status 0x%08lx\n", Status); - ObDereferenceObject(PhysicalDeviceObject); - return Status; - } + DPRINT1("IopGetDeviceObjectFromDeviceInstance failed to find device object for %wZ\n", &DeviceInstance); + ExFreePoolWithTag(DeviceInstance.Buffer, TAG_IO); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + ExFreePoolWithTag(DeviceInstance.Buffer, TAG_IO);
EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL; IopNotifyPlugPlayNotification(