\r
Manage Usb Descriptor List\r
\r
-Copyright (c) 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
@param Setting The descriptor to free.\r
\r
- @return None.\r
-\r
**/\r
VOID\r
UsbFreeInterfaceDesc (\r
Ep = Setting->Endpoints[Index];\r
\r
if (Ep != NULL) {\r
- gBS->FreePool (Ep);\r
+ FreePool (Ep);\r
}\r
}\r
\r
- gBS->FreePool (Setting->Endpoints);\r
+ //\r
+ // Only call FreePool() if NumEndpoints > 0.\r
+ //\r
+ if (Setting->Desc.NumEndpoints > 0) {\r
+ FreePool (Setting->Endpoints);\r
+ }\r
}\r
\r
- gBS->FreePool (Setting);\r
+ FreePool (Setting);\r
}\r
\r
\r
\r
@param Config The configuration descriptor to free.\r
\r
- @return None.\r
-\r
**/\r
VOID\r
UsbFreeConfigDesc (\r
}\r
}\r
\r
- gBS->FreePool (Interface);\r
+ FreePool (Interface);\r
}\r
\r
- gBS->FreePool (Config->Interfaces);\r
+ FreePool (Config->Interfaces);\r
}\r
\r
- gBS->FreePool (Config);\r
+ FreePool (Config);\r
\r
}\r
\r
\r
@param DevDesc The device descriptor.\r
\r
- @return None.\r
-\r
**/\r
VOID\r
UsbFreeDevDesc (\r
}\r
}\r
\r
- gBS->FreePool (DevDesc->Configs);\r
+ FreePool (DevDesc->Configs);\r
}\r
\r
- gBS->FreePool (DevDesc);\r
+ FreePool (DevDesc);\r
}\r
\r
\r
Create a descriptor.\r
\r
@param DescBuf The buffer of raw descriptor.\r
- @param Len The lenght of the raw descriptor buffer.\r
+ @param Len The length of the raw descriptor buffer.\r
@param Type The type of descriptor to create.\r
@param Consumed Number of bytes consumed.\r
\r
VOID *\r
UsbCreateDesc (\r
IN UINT8 *DescBuf,\r
- IN INTN Len,\r
+ IN UINTN Len,\r
IN UINT8 Type,\r
- OUT INTN *Consumed\r
+ OUT UINTN *Consumed\r
)\r
{\r
USB_DESC_HEAD *Head;\r
- INTN DescLen;\r
- INTN CtrlLen;\r
- INTN Offset;\r
+ UINTN DescLen;\r
+ UINTN CtrlLen;\r
+ UINTN Offset;\r
VOID *Desc;\r
\r
DescLen = 0;\r
DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
CtrlLen = sizeof (USB_ENDPOINT_DESC);\r
break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Total length is too small that cannot hold the single descriptor header plus data.\r
+ //\r
+ if (Len <= sizeof (USB_DESC_HEAD)) {\r
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, total length = %d!\n", Len));\r
+ return NULL;\r
}\r
\r
//\r
// format. Skip the descriptor that isn't of this Type\r
//\r
Offset = 0;\r
- Head = (USB_DESC_HEAD*)DescBuf;\r
+ Head = (USB_DESC_HEAD *)DescBuf;\r
+ while (Offset < Len - sizeof (USB_DESC_HEAD)) {\r
+ //\r
+ // Above condition make sure Head->Len and Head->Type are safe to access\r
+ //\r
+ Head = (USB_DESC_HEAD *)&DescBuf[Offset];\r
+\r
+ if (Head->Len == 0) {\r
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n"));\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Make sure no overflow when adding Head->Len to Offset.\r
+ //\r
+ if (Head->Len > MAX_UINTN - Offset) {\r
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = %d!\n", Head->Len));\r
+ return NULL;\r
+ }\r
\r
- while ((Offset < Len) && (Head->Type != Type)) {\r
Offset += Head->Len;\r
- Head = (USB_DESC_HEAD*)(DescBuf + Offset);\r
+\r
+ if (Head->Type == Type) {\r
+ break;\r
+ }\r
}\r
\r
- if ((Len <= Offset) || (Len < Offset + DescLen) ||\r
- (Head->Type != Type) || (Head->Len != DescLen)) {\r
- DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor\n"));\r
+ //\r
+ // Head->Len is invalid resulting data beyond boundary, or\r
+ // Descriptor cannot be found: No such type.\r
+ //\r
+ if (Len < Offset) {\r
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Len));\r
return NULL;\r
}\r
\r
- Desc = AllocateZeroPool (CtrlLen);\r
+ if ((Head->Type != Type) || (Head->Len < DescLen)) {\r
+ DEBUG ((DEBUG_ERROR, "UsbCreateDesc: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));\r
+ return NULL;\r
+ }\r
\r
+ Desc = AllocateZeroPool ((UINTN) CtrlLen);\r
if (Desc == NULL) {\r
return NULL;\r
}\r
\r
- CopyMem (Desc, Head, DescLen);\r
- *Consumed = Offset + Head->Len;\r
+ CopyMem (Desc, Head, (UINTN) DescLen);\r
+\r
+ *Consumed = Offset;\r
\r
return Desc;\r
}\r
\r
\r
/**\r
- Parse an interface desciptor and its endpoints.\r
+ Parse an interface descriptor and its endpoints.\r
\r
@param DescBuf The buffer of raw descriptor.\r
- @param Len The lenght of the raw descriptor buffer.\r
+ @param Len The length of the raw descriptor buffer.\r
@param Consumed The number of raw descriptor consumed.\r
\r
@return The create interface setting or NULL if failed.\r
USB_INTERFACE_SETTING *\r
UsbParseInterfaceDesc (\r
IN UINT8 *DescBuf,\r
- IN INTN Len,\r
- OUT INTN *Consumed\r
+ IN UINTN Len,\r
+ OUT UINTN *Consumed\r
)\r
{\r
USB_INTERFACE_SETTING *Setting;\r
USB_ENDPOINT_DESC *Ep;\r
UINTN Index;\r
UINTN NumEp;\r
- INTN Used;\r
- INTN Offset;\r
+ UINTN Used;\r
+ UINTN Offset;\r
\r
*Consumed = 0;\r
Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);\r
Offset = Used;\r
\r
//\r
- // Create an arry to hold the interface's endpoints\r
+ // Create an array to hold the interface's endpoints\r
//\r
NumEp = Setting->Desc.NumEndpoints;\r
\r
//\r
// Create the endpoints for this interface\r
//\r
- for (Index = 0; Index < NumEp; Index++) {\r
+ for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) {\r
Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);\r
\r
if (Ep == NULL) {\r
Parse the configuration descriptor and its interfaces.\r
\r
@param DescBuf The buffer of raw descriptor.\r
- @param Len The lenght of the raw descriptor buffer.\r
+ @param Len The length of the raw descriptor buffer.\r
\r
@return The created configuration descriptor.\r
\r
USB_CONFIG_DESC *\r
UsbParseConfigDesc (\r
IN UINT8 *DescBuf,\r
- IN INTN Len\r
+ IN UINTN Len\r
)\r
{\r
USB_CONFIG_DESC *Config;\r
USB_INTERFACE_DESC *Interface;\r
UINTN Index;\r
UINTN NumIf;\r
- INTN Consumed;\r
+ UINTN Consumed;\r
\r
ASSERT (DescBuf != NULL);\r
\r
DescBuf += Consumed;\r
Len -= Consumed;\r
\r
- while (Len > 0) {\r
+ //\r
+ // Make allowances for devices that return extra data at the\r
+ // end of their config descriptors\r
+ //\r
+ while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {\r
Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);\r
\r
- if ((Setting == NULL)) {\r
- DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: failed to parse interface setting\n"));\r
- goto ON_ERROR;\r
+ if (Setting == NULL) {\r
+ DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n"));\r
+ break;\r
\r
} else if (Setting->Desc.InterfaceNumber >= NumIf) {\r
DEBUG (( EFI_D_ERROR, "UsbParseConfigDesc: mal-formated interface descriptor\n"));\r
// Get the first 8 bytes of the device descriptor which contains\r
// max packet size for endpoint 0, which is at least 8.\r
//\r
- UsbDev->MaxPacket0 = 8;\r
-\r
for (Index = 0; Index < 3; Index++) {\r
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);\r
\r
if (!EFI_ERROR (Status)) {\r
+ if ((DevDesc.BcdUSB >= 0x0300) && (DevDesc.MaxPacketSize0 == 9)) {\r
+ UsbDev->MaxPacket0 = 1 << 9;\r
+ return EFI_SUCCESS;\r
+ }\r
UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;\r
return EFI_SUCCESS;\r
}\r
//\r
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);\r
\r
- if (EFI_ERROR (Status)) {\r
+ //\r
+ // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.\r
+ //\r
+ if (EFI_ERROR (Status) ||\r
+ (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||\r
+ (Desc.Length % 2 != 0)\r
+ ) {\r
return NULL;\r
}\r
\r
);\r
\r
if (EFI_ERROR (Status)) {\r
- gBS->FreePool (Buf);\r
+ FreePool (Buf);\r
return NULL;\r
}\r
\r
Status = EFI_SUCCESS;\r
\r
Max = (Desc->Length - 2) / 2;\r
- Max = (Max < USB_MAX_LANG_ID ? Max : USB_MAX_LANG_ID);\r
+ Max = MIN(Max, USB_MAX_LANG_ID);\r
\r
Point = Desc->String;\r
for (Index = 0; Index < Max; Index++) {\r
\r
/**\r
Retrieve the indexed configure for the device. USB device\r
- returns the configuration togetther with the interfaces for\r
+ returns the configuration together with the interfaces for\r
this configuration. Configuration descriptor is also of\r
variable length.\r
\r
\r
DEBUG (( EFI_D_INFO, "UsbGetOneConfig: total length is %d\n", Desc.TotalLength));\r
\r
+ //\r
+ // Reject if TotalLength even cannot cover itself.\r
+ //\r
+ if (Desc.TotalLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (Desc.TotalLength)) {\r
+ return NULL;\r
+ }\r
+\r
Buf = AllocateZeroPool (Desc.TotalLength);\r
\r
if (Buf == NULL) {\r
if (EFI_ERROR (Status)) {\r
DEBUG (( EFI_D_ERROR, "UsbGetOneConfig: failed to get full descript %r\n", Status));\r
\r
- gBS->FreePool (Buf);\r
+ FreePool (Buf);\r
return NULL;\r
}\r
\r
return Status;\r
}\r
\r
- DevDesc = UsbDev->DevDesc;\r
- NumConfig = DevDesc->Desc.NumConfigurations;\r
- DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));\r
+ DevDesc = UsbDev->DevDesc;\r
+ NumConfig = DevDesc->Desc.NumConfigurations;\r
+ if (NumConfig == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
+ DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));\r
if (DevDesc->Configs == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
ConfigDesc = UsbParseConfigDesc ((UINT8 *) Config, Config->TotalLength);\r
\r
- gBS->FreePool (Config);\r
+ FreePool (Config);\r
\r
if (ConfigDesc == NULL) {\r
DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: failed to parse configure (index %d)\n", Index));\r
Status = UsbBuildLangTable (UsbDev);\r
\r
if (EFI_ERROR (Status)) {\r
- DEBUG (( EFI_D_ERROR, "UsbBuildDescTable: get language ID table %r\n", Status));\r
+ DEBUG (( EFI_D_INFO, "UsbBuildDescTable: get language ID table %r\n", Status));\r
}\r
\r
return EFI_SUCCESS;\r