[USBSTOR] Fix PdoHandleQueryInstanceId and increase serial number descriptor size to MAXIMUM_USB_STRING_LENGTH (#6413)

Serial number on some USB devices might exceed the number of 100 characters
(e.g. 120 characters on "SanDisk Ultra 3.2Gen1" pendrive) and cause buffer
overflow, resulting in usbstor.sys crash.

- Use pool allocation for instance ID generation.
  Fixes stack overflow on USB storage devices with large serial number.
- Print the LUN number as a hexadecimal, not as a character.
- Verify the serial number descriptor before using it.
- Increase the max descriptor size for serial number to
  MAXIMUM_USB_STRING_LENGTH. This fixes serial number string truncation.

Based on suggestions by disean and ThFabba.

CORE-17625
This commit is contained in:
Adam Słaboń 2024-02-16 16:48:33 +01:00 committed by GitHub
parent 398201dca4
commit 20efea8fa4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 16 deletions

View file

@ -118,7 +118,7 @@ USBSTOR_GetDescriptors(
if (DeviceExtension->DeviceDescriptor->iSerialNumber) if (DeviceExtension->DeviceDescriptor->iSerialNumber)
{ {
// get serial number // get serial number
Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber); Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, MAXIMUM_USB_STRING_LENGTH, DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
FreeItem(DeviceExtension->DeviceDescriptor); FreeItem(DeviceExtension->DeviceDescriptor);

View file

@ -437,37 +437,60 @@ USBSTOR_PdoHandleQueryInstanceId(
{ {
PPDO_DEVICE_EXTENSION PDODeviceExtension; PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension; PFDO_DEVICE_EXTENSION FDODeviceExtension;
WCHAR Buffer[100]; PUSB_STRING_DESCRIPTOR Descriptor;
ULONG Length; ULONG CharCount;
LPWSTR InstanceId; LPWSTR InstanceId;
NTSTATUS Status;
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; PDODeviceExtension = DeviceObject->DeviceExtension;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; FDODeviceExtension = PDODeviceExtension->LowerDeviceObject->DeviceExtension;
// format instance id Descriptor = FDODeviceExtension->SerialNumber;
if (FDODeviceExtension->SerialNumber) if (Descriptor && (Descriptor->bLength >= sizeof(USB_COMMON_DESCRIPTOR) + sizeof(WCHAR)))
{ {
// using serial number from device /* Format the serial number descriptor only if supported by the device */
swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN); CharCount = (Descriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR) +
(sizeof("&") - 1) +
(sizeof("F") - 1) + // LUN: 1 char (MAX_LUN)
sizeof(ANSI_NULL);
} }
else else
{ {
// use instance count and LUN /* Use the instance count and LUN as a fallback */
swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN); CharCount = (sizeof("99999999") - 1) + // Instance Count: 8 chars
(sizeof("&") - 1) +
(sizeof("F") - 1) + // LUN: 1 char (MAX_LUN)
sizeof(ANSI_NULL);
} }
Length = wcslen(Buffer) + 1; InstanceId = ExAllocatePoolUninitialized(PagedPool, CharCount * sizeof(WCHAR), USB_STOR_TAG);
InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), USB_STOR_TAG);
if (!InstanceId) if (!InstanceId)
{ {
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
} }
wcscpy(InstanceId, Buffer); if (Descriptor && (Descriptor->bLength >= sizeof(USB_COMMON_DESCRIPTOR) + sizeof(WCHAR)))
{
Status = RtlStringCchPrintfW(InstanceId,
CharCount,
L"%s&%x",
Descriptor->bString,
PDODeviceExtension->LUN);
}
else
{
Status = RtlStringCchPrintfW(InstanceId,
CharCount,
L"%04lu&%x",
FDODeviceExtension->InstanceCount,
PDODeviceExtension->LUN);
}
DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId); /* This should not happen */
ASSERT(NT_SUCCESS(Status));
DPRINT("USBSTOR_PdoHandleQueryInstanceId '%S'\n", InstanceId);
Irp->IoStatus.Information = (ULONG_PTR)InstanceId; Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
return STATUS_SUCCESS; return STATUS_SUCCESS;

View file

@ -2,6 +2,7 @@
#define _USBSTOR_H_ #define _USBSTOR_H_
#include <wdm.h> #include <wdm.h>
#include <ntstrsafe.h>
#include <usbdi.h> #include <usbdi.h>
#include <usbbusif.h> #include <usbbusif.h>
#include <usbdlib.h> #include <usbdlib.h>