staging: rtl8712: handle firmware load failure
authorRustam Kovhaev <rkovhaev@gmail.com>
Thu, 16 Jul 2020 15:13:26 +0000 (08:13 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Jul 2020 10:08:44 +0000 (12:08 +0200)
when firmware fails to load we should not call unregister_netdev()
this patch fixes a race condition between rtl871x_load_fw_cb() and
r871xu_dev_remove() and fixes the bug reported by syzbot

Reported-by: syzbot+80899a8a8efe8968cde7@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=80899a8a8efe8968cde7
Signed-off-by: Rustam Kovhaev <rkovhaev@gmail.com>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20200716151324.1036204-1-rkovhaev@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/rtl8712/hal_init.c
drivers/staging/rtl8712/usb_intf.c

index ed51023..715f1fe 100644 (file)
@@ -33,7 +33,6 @@ static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
 {
        struct _adapter *adapter = context;
 
-       complete(&adapter->rtl8712_fw_ready);
        if (!firmware) {
                struct usb_device *udev = adapter->dvobjpriv.pusbdev;
                struct usb_interface *usb_intf = adapter->pusb_intf;
@@ -41,11 +40,13 @@ static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
                dev_err(&udev->dev, "r8712u: Firmware request failed\n");
                usb_put_dev(udev);
                usb_set_intfdata(usb_intf, NULL);
+               complete(&adapter->rtl8712_fw_ready);
                return;
        }
        adapter->fw = firmware;
        /* firmware available - start netdev */
        register_netdev(adapter->pnetdev);
+       complete(&adapter->rtl8712_fw_ready);
 }
 
 static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
index a87562f..2fcd652 100644 (file)
@@ -595,13 +595,17 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
        if (pnetdev) {
                struct _adapter *padapter = netdev_priv(pnetdev);
 
-               usb_set_intfdata(pusb_intf, NULL);
-               release_firmware(padapter->fw);
                /* never exit with a firmware callback pending */
                wait_for_completion(&padapter->rtl8712_fw_ready);
+               pnetdev = usb_get_intfdata(pusb_intf);
+               usb_set_intfdata(pusb_intf, NULL);
+               if (!pnetdev)
+                       goto firmware_load_fail;
+               release_firmware(padapter->fw);
                if (drvpriv.drv_registered)
                        padapter->surprise_removed = true;
-               unregister_netdev(pnetdev); /* will call netdev_close() */
+               if (pnetdev->reg_state != NETREG_UNINITIALIZED)
+                       unregister_netdev(pnetdev); /* will call netdev_close() */
                flush_scheduled_work();
                udelay(1);
                /* Stop driver mlme relation timer */
@@ -614,6 +618,7 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
                 */
                usb_put_dev(udev);
        }
+firmware_load_fail:
        /* If we didn't unplug usb dongle and remove/insert module, driver
         * fails on sitesurvey for the first time when device is up.
         * Reset usb port for sitesurvey fail issue.