powerpc/eeh: Fix use-after-release of EEH driver
authorSam Bobroff <sbobroff@linux.ibm.com>
Fri, 25 May 2018 03:11:30 +0000 (13:11 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 3 Jun 2018 10:43:38 +0000 (20:43 +1000)
Correct two cases where eeh_pcid_get() is used to reference the driver's
module but the reference is dropped before the driver pointer is used.

In eeh_rmv_device() also refactor a little so that only two calls to
eeh_pcid_put() are needed, rather than three and the reference isn't
taken at all if it wasn't needed.

Signed-off-by: Sam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/kernel/eeh_driver.c

index 07e0a42..54333f6 100644 (file)
@@ -458,9 +458,11 @@ static void *eeh_add_virt_device(void *data, void *userdata)
 
        driver = eeh_pcid_get(dev);
        if (driver) {
-               eeh_pcid_put(dev);
-               if (driver->err_handler)
+               if (driver->err_handler) {
+                       eeh_pcid_put(dev);
                        return NULL;
+               }
+               eeh_pcid_put(dev);
        }
 
 #ifdef CONFIG_PCI_IOV
@@ -497,17 +499,19 @@ static void *eeh_rmv_device(void *data, void *userdata)
        if (eeh_dev_removed(edev))
                return NULL;
 
-       driver = eeh_pcid_get(dev);
-       if (driver) {
-               eeh_pcid_put(dev);
-               if (removed &&
-                   eeh_pe_passed(edev->pe))
-                       return NULL;
-               if (removed &&
-                   driver->err_handler &&
-                   driver->err_handler->error_detected &&
-                   driver->err_handler->slot_reset)
+       if (removed) {
+               if (eeh_pe_passed(edev->pe))
                        return NULL;
+               driver = eeh_pcid_get(dev);
+               if (driver) {
+                       if (driver->err_handler &&
+                           driver->err_handler->error_detected &&
+                           driver->err_handler->slot_reset) {
+                               eeh_pcid_put(dev);
+                               return NULL;
+                       }
+                       eeh_pcid_put(dev);
+               }
        }
 
        /* Remove it from PCI subsystem */