The entry point of the driver, InitializePciHostBridge(), leaks resources
(and installed protocols) in the following cases:

- The first root bridge protocol installation fails. In this case, the
  host bridge protocol is left installed, but the driver exits with an
  error.

- The second or a later root bridge protocol installation fails. In this
  case, the host bridge protocol, and all prior root bridge protocols, are
  left installed, even though the driver exits with an error.

Handle errors correctly: roll back / release / uninstall resources when
aborting the driver.

Cc: Jordan Justen <jordan.l.jus...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
Regression-tested-by: Gabriel Somlo <so...@cmu.edu>
---
 OvmfPkg/PciHostBridgeDxe/PciHostBridge.c | 54 ++++++++++++++++++--
 1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c 
b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
index 7ca0b6e..a5dbe57 100644
--- a/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
+++ b/OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
@@ -154,6 +154,32 @@ FreePrivateData:
 
 
 /**
+  Uninitialize and free a root bridge set up with InitRootBridge().
+
+  On return, the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance and the device path
+  will have been released, freeing RootBus->Handle as well.
+
+  param[in] RootBus  The private PCI_ROOT_BRIDGE_INSTANCE that has been created
+                     with InitRootBridge(), and should be released.
+**/
+STATIC
+VOID
+UninitRootBridge (
+  IN PCI_ROOT_BRIDGE_INSTANCE *RootBus
+  )
+{
+  EFI_STATUS Status;
+
+  Status = gBS->UninstallMultipleProtocolInterfaces (RootBus->Handle,
+                  &gEfiDevicePathProtocolGuid,      &RootBus->DevicePath,
+                  &gEfiPciRootBridgeIoProtocolGuid, &RootBus->Io,
+                  NULL);
+  ASSERT_EFI_ERROR (Status);
+  FreePool (RootBus);
+}
+
+
+/**
   Entry point of this driver
 
   @param ImageHandle     Handle of driver image
@@ -174,6 +200,7 @@ InitializePciHostBridge (
   UINTN                       RootBridgeNumber;
   PCI_HOST_BRIDGE_INSTANCE    *HostBridge;
   PCI_ROOT_BRIDGE_INSTANCE    *RootBus;
+  EFI_STATUS                  UninstallStatus;
 
   mDriverImageHandle = ImageHandle;
 
@@ -196,8 +223,7 @@ InitializePciHostBridge (
                   NULL
                   );
   if (EFI_ERROR (Status)) {
-    FreePool (HostBridge);
-    return EFI_DEVICE_ERROR;
+    goto FreeHostBridge;
   }
 
   for (RootBridgeNumber = 0;
@@ -209,12 +235,34 @@ InitializePciHostBridge (
                &RootBus
                );
     if (EFI_ERROR (Status)) {
-      return Status;
+      goto RollbackProtocols;
     }
     InsertTailList (&HostBridge->Head, &RootBus->Link);
   }
 
   return EFI_SUCCESS;
+
+RollbackProtocols:
+  while (!IsListEmpty (&HostBridge->Head)) {
+    LIST_ENTRY *Entry;
+
+    Entry = GetFirstNode (&HostBridge->Head);
+    RemoveEntryList (Entry);
+    RootBus = DRIVER_INSTANCE_FROM_LIST_ENTRY (Entry);
+    UninitRootBridge (RootBus);
+  }
+  UninstallStatus = gBS->UninstallMultipleProtocolInterfaces (
+                           HostBridge->HostBridgeHandle,
+                           &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+                           &HostBridge->ResAlloc,
+                           NULL
+                           );
+  ASSERT_EFI_ERROR (UninstallStatus);
+
+FreeHostBridge:
+  FreePool (HostBridge);
+
+  return Status;
 }
 
 
-- 
1.8.3.1



------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that
you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to