1) Remove buffer overflow when the number of Driver Binding Protocols increases in...
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Core / Dxe / Hand / DriverSupport.c
index e8a400c..511acff 100644 (file)
@@ -23,20 +23,17 @@ Revision History
 \r
 #include <DxeMain.h>\r
 \r
+BOOLEAN mRepairLoadedImage = FALSE;\r
 \r
-\r
-STATIC\r
+//\r
+// Driver Support Function Prototypes\r
+//\r
 EFI_STATUS\r
 GetHandleFromDriverBinding (\r
   IN EFI_DRIVER_BINDING_PROTOCOL           *DriverBindingNeed,\r
   OUT  EFI_HANDLE                          *Handle \r
   );\r
 \r
-\r
-//\r
-// Driver Support Function Prototypes\r
-//\r
-STATIC\r
 EFI_STATUS \r
 CoreConnectSingleController (\r
   IN  EFI_HANDLE                ControllerHandle,\r
@@ -47,8 +44,6 @@ CoreConnectSingleController (
 //\r
 // Driver Support Functions\r
 //\r
-\r
-\r
 EFI_STATUS \r
 EFIAPI\r
 CoreConnectController (\r
@@ -88,6 +83,14 @@ Returns:
   LIST_ENTRY                           *ProtLink;\r
   OPEN_PROTOCOL_DATA                   *OpenData;\r
   EFI_DEVICE_PATH_PROTOCOL             *AlignedRemainingDevicePath;\r
+  EFI_HANDLE                           *ChildHandleBuffer;\r
+  UINTN                                ChildHandleCount;\r
+  UINTN                                Index;\r
+  EFI_HANDLE                           *LoadedImageHandleBuffer;\r
+  UINTN                                LoadedImageHandleCount;\r
+  LOADED_IMAGE_PRIVATE_DATA            *Image;\r
+  EFI_HANDLE                           DeviceHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL             *DevicePath;\r
   \r
   //\r
   // Make sure ControllerHandle is valid\r
@@ -100,56 +103,179 @@ Returns:
   Handle = ControllerHandle;\r
 \r
   //\r
-  // Connect all drivers to ControllerHandle \r
+  // Make a copy of RemainingDevicePath to guanatee it is aligned\r
   //\r
   AlignedRemainingDevicePath = NULL;\r
   if (RemainingDevicePath != NULL) {\r
     AlignedRemainingDevicePath = CoreDuplicateDevicePath (RemainingDevicePath);\r
   }\r
-  ReturnStatus = CoreConnectSingleController (\r
-                   ControllerHandle,\r
-                   DriverImageHandle,\r
-                   AlignedRemainingDevicePath\r
-                   );\r
-  if (AlignedRemainingDevicePath != NULL) {\r
-    CoreFreePool (AlignedRemainingDevicePath);\r
-  }\r
 \r
   //\r
-  // If not recursive, then just return after connecting drivers to ControllerHandle\r
+  // Connect all drivers to ControllerHandle\r
+  // If CoreConnectSingleController returns EFI_NOT_READY, then the number of\r
+  // Driver Binding Protocols in the handle database has increased during the call\r
+  // so the connect operation must be restarted\r
   //\r
-  if (!Recursive) {\r
-    return ReturnStatus;\r
+  do {\r
+    ReturnStatus = CoreConnectSingleController (\r
+                    ControllerHandle,\r
+                    DriverImageHandle,\r
+                    AlignedRemainingDevicePath\r
+                    );\r
+  } while (ReturnStatus == EFI_NOT_READY);\r
+\r
+  //\r
+  // Free the aligned copy of RemainingDevicePath\r
+  //\r
+  if (AlignedRemainingDevicePath != NULL) {\r
+    CoreFreePool (AlignedRemainingDevicePath);\r
   }\r
 \r
   //\r
   // If recursive, then connect all drivers to all of ControllerHandle's children\r
   //\r
-  CoreAcquireProtocolLock ();\r
-  for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
-    Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
-    for (ProtLink = Prot->OpenList.ForwardLink; \r
-           ProtLink != &Prot->OpenList; \r
-           ProtLink = ProtLink->ForwardLink) {\r
+  if (Recursive) {\r
+    //\r
+    // Acquire the protocol lock on the handle database so the child handles can be collected\r
+    //\r
+    CoreAcquireProtocolLock ();\r
+\r
+    //\r
+    // Make sure the DriverBindingHandle is valid\r
+    //\r
+    Status = CoreValidateHandle (ControllerHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Release the protocol lock on the handle database\r
+      //\r
+      CoreReleaseProtocolLock ();\r
+\r
+      return ReturnStatus;\r
+    }\r
+\r
+\r
+    //\r
+    // Count ControllerHandle's children\r
+    //\r
+    for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+      for (ProtLink = Prot->OpenList.ForwardLink; \r
+          ProtLink != &Prot->OpenList; \r
+          ProtLink = ProtLink->ForwardLink) {\r
         OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
         if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
-          CoreReleaseProtocolLock ();\r
-          Status = CoreConnectController (\r
-                          OpenData->ControllerHandle,\r
-                          NULL,\r
-                          NULL,\r
-                          TRUE\r
-                          ); \r
-          CoreAcquireProtocolLock ();\r
+          ChildHandleCount++;\r
         }\r
+      }\r
     }\r
+\r
+    //\r
+    // Allocate a handle buffer for ControllerHandle's children\r
+    //\r
+    ChildHandleBuffer = CoreAllocateBootServicesPool (ChildHandleCount * sizeof(EFI_HANDLE));\r
+\r
+    //\r
+    // Fill in a handle buffer with ControllerHandle's children\r
+    //\r
+    for (Link = Handle->Protocols.ForwardLink, ChildHandleCount = 0; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+      Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+      for (ProtLink = Prot->OpenList.ForwardLink; \r
+          ProtLink != &Prot->OpenList; \r
+          ProtLink = ProtLink->ForwardLink) {\r
+        OpenData = CR (ProtLink, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
+        if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+          ChildHandleBuffer[ChildHandleCount] = OpenData->ControllerHandle;\r
+          ChildHandleCount++;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Release the protocol lock on the handle database\r
+    //\r
+    CoreReleaseProtocolLock ();\r
+\r
+    //\r
+    // Recursively connect each child handle\r
+    //\r
+    for (Index = 0; Index < ChildHandleCount; Index++) {\r
+      CoreConnectController (\r
+        ChildHandleBuffer[Index],\r
+        NULL,\r
+        NULL,\r
+        TRUE\r
+        ); \r
+    }\r
+\r
+    //\r
+    // Free the handle buffer of ControllerHandle's children\r
+    //\r
+    CoreFreePool (ChildHandleBuffer);\r
   }\r
-  CoreReleaseProtocolLock ();\r
-  \r
+\r
+  //\r
+  // If a Stop() function has been called one or more time successfully, then attempt to \r
+  // repair the stale DeviceHandle fields of the Loaded Image Protocols\r
+  //\r
+  if (mRepairLoadedImage) {\r
+    //\r
+    // Assume that all Loaded Image Protocols can be repaired\r
+    //\r
+    mRepairLoadedImage = FALSE;\r
+\r
+    //\r
+    // Get list of all Loaded Image Protocol Instances\r
+    //\r
+    Status = CoreLocateHandleBuffer (\r
+              ByProtocol,   \r
+              &gEfiLoadedImageProtocolGuid,  \r
+              NULL,\r
+              &LoadedImageHandleCount, \r
+              &LoadedImageHandleBuffer\r
+              );\r
+    if (!EFI_ERROR (Status) && LoadedImageHandleCount != 0) {\r
+      for (Index = 0; Index < LoadedImageHandleCount; Index++) {\r
+        //\r
+        // Retrieve the Loaded Image Protocol\r
+        //\r
+        Image = CoreLoadedImageInfo (LoadedImageHandleBuffer[Index]);\r
+        if (Image != NULL) {\r
+          //\r
+          // Check to see if the DeviceHandle field is a valid handle\r
+          //\r
+          Status = CoreValidateHandle (Image->Info.DeviceHandle);\r
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // The DeviceHandle field is not valid.\r
+            // Attempt to locate a device handle with a device path that matches the one\r
+            // that was used to originally load the image\r
+            //\r
+            DevicePath = Image->DeviceHandleDevicePath;\r
+            if (DevicePath != NULL) {\r
+              Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &DeviceHandle);\r
+              if (!EFI_ERROR (Status) && (DeviceHandle != NULL_HANDLE) && IsDevicePathEnd(DevicePath)) {\r
+                //\r
+                // A device handle with a matching device path was found, so update the Loaded Image Protocol\r
+                // with the device handle discovered\r
+                //\r
+                Image->Info.DeviceHandle = DeviceHandle;\r
+              } else {\r
+                //\r
+                // There is still at least one Loaded Image Protocol that requires repair\r
+                //\r
+                mRepairLoadedImage = TRUE;\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+      CoreFreePool (LoadedImageHandleBuffer);\r
+    }\r
+  }\r
+\r
   return ReturnStatus;\r
 }\r
 \r
-STATIC\r
 VOID\r
 AddSortedDriverBindingProtocol (\r
   IN      EFI_HANDLE                   DriverBindingHandle,\r
@@ -213,7 +339,7 @@ Returns:
   //\r
   // See if DriverBinding is already in the sorted list\r
   //\r
-  for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols; Index++) {\r
+  for (Index = 0; Index < *NumberOfSortedDriverBindingProtocols && Index < DriverBindingHandleCount; Index++) {\r
     if (DriverBinding == SortedDriverBindingProtocols[Index]) {\r
       return;\r
     }\r
@@ -222,7 +348,9 @@ Returns:
   //\r
   // Add DriverBinding to the end of the list\r
   //\r
-  SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;\r
+  if (*NumberOfSortedDriverBindingProtocols < DriverBindingHandleCount) {\r
+    SortedDriverBindingProtocols[*NumberOfSortedDriverBindingProtocols] = DriverBinding;\r
+  }\r
   *NumberOfSortedDriverBindingProtocols = *NumberOfSortedDriverBindingProtocols + 1;\r
 \r
   //\r
@@ -235,7 +363,6 @@ Returns:
   }\r
 }\r
  \r
-STATIC\r
 EFI_STATUS \r
 CoreConnectSingleController (\r
   IN  EFI_HANDLE                ControllerHandle,\r
@@ -404,6 +531,19 @@ Returns:
   //\r
   CoreFreePool (DriverBindingHandleBuffer);\r
 \r
+  //\r
+  // If the number of Driver Binding Protocols has increased since this function started, then return\r
+  // EFI_NOT_READY, so it will be restarted\r
+  //\r
+  if (NumberOfSortedDriverBindingProtocols > DriverBindingHandleCount) {\r
+    //\r
+    // Free any buffers that were allocated with AllocatePool()\r
+    //\r
+    CoreFreePool (SortedDriverBindingProtocols);\r
+\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
   //\r
   // Sort the remaining DriverBinding Protocol based on their Version field from\r
   // highest to lowest.\r
@@ -555,6 +695,9 @@ Returns:
   OPEN_PROTOCOL_DATA                  *OpenData;\r
   PROTOCOL_INTERFACE                  *Prot;\r
   EFI_DRIVER_BINDING_PROTOCOL         *DriverBinding;\r
+  EFI_HANDLE                          *LoadedImageHandleBuffer;\r
+  UINTN                               LoadedImageHandleCount;\r
+  LOADED_IMAGE_PRIVATE_DATA           *Image;\r
 \r
   //\r
   // Make sure ControllerHandle is valid\r
@@ -756,6 +899,49 @@ Returns:
   }\r
 \r
   if (StopCount > 0) {\r
+    //\r
+    // If the Loaded Image Protocols do not already need to be repaired, then\r
+    // check the status of the DeviceHandle field of all Loaded Image Protocols\r
+    // to determine if any of them now need repair because a sucessful Stop()\r
+    // may have destroyed the DeviceHandle value in the Loaded Image Protocol\r
+    //\r
+    if (!mRepairLoadedImage) {\r
+      //\r
+      // Get list of all Loaded Image Protocol Instances\r
+      //\r
+      Status = CoreLocateHandleBuffer (\r
+                ByProtocol,   \r
+                &gEfiLoadedImageProtocolGuid,  \r
+                NULL,\r
+                &LoadedImageHandleCount, \r
+                &LoadedImageHandleBuffer\r
+                );\r
+      if (!EFI_ERROR (Status) && LoadedImageHandleCount != 0) {\r
+        for (Index = 0; Index < LoadedImageHandleCount; Index++) {\r
+          //\r
+          // Retrieve the Loaded Image Protocol\r
+          //\r
+          Image = CoreLoadedImageInfo (LoadedImageHandleBuffer[Index]);\r
+          if (Image != NULL) {\r
+            //\r
+            // Check to see if the DeviceHandle field is a valid handle\r
+            //\r
+            Status = CoreValidateHandle (Image->Info.DeviceHandle);\r
+            if (EFI_ERROR (Status)) {\r
+              //\r
+              // The DeviceHandle field is not longer a valid handle.  This means\r
+              // that future calls to ConnectController() need to attemp to repair\r
+              // the Loaded Image Protocols with invalid DeviceHandle fields.  Set \r
+              // the flag used by ConnectController().\r
+              //\r
+              mRepairLoadedImage = TRUE;\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        CoreFreePool (LoadedImageHandleBuffer);\r
+      }\r
+    }\r
     Status = EFI_SUCCESS;\r
   } else {\r
     Status = EFI_NOT_FOUND;\r
@@ -770,9 +956,6 @@ Done:
   return Status;\r
 }\r
 \r
-\r
-\r
-STATIC\r
 EFI_STATUS\r
 GetHandleFromDriverBinding (\r
   IN   EFI_DRIVER_BINDING_PROTOCOL           *DriverBindingNeed,\r