Skip to content

Commit

Permalink
staging: rtl8712: error handling refactoring
Browse files Browse the repository at this point in the history
commit e9e6aa5 upstream.

There was strange error handling logic in case of fw load failure. For
some reason fw loader callback was doing clean up stuff when fw is not
available. I don't see any reason behind doing this. Since this driver
doesn't have EEPROM firmware let's just disconnect it in case of fw load
failure. Doing clean up stuff in 2 different place which can run
concurently is not good idea and syzbot found 2 bugs related to this
strange approach.

So, in this pacth I deleted all clean up code from fw callback and made
a call to device_release_driver() under device_lock(parent) in case of fw
load failure. This approach is more generic and it defend driver from UAF
bugs, since all clean up code is moved to one place.

Fixes: e02a3b9 ("staging: rtl8712: fix memory leak in rtl871x_load_fw_cb")
Fixes: 8c213fa ("staging: r8712u: Use asynchronous firmware loading")
Cc: stable <stable@vger.kernel.org>
Reported-and-tested-by: syzbot+5872a520e0ce0a7c7230@syzkaller.appspotmail.com
Reported-and-tested-by: syzbot+cc699626e48a6ebaf295@syzkaller.appspotmail.com
Signed-off-by: Pavel Skripkin <paskripkin@gmail.com>
Link: https://lore.kernel.org/r/d49ecc56e97c4df181d7bd4d240b031f315eacc3.1626895918.git.paskripkin@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
pskrgag authored and gregkh committed Aug 12, 2021
1 parent e756548 commit 9f57b94
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 39 deletions.
30 changes: 20 additions & 10 deletions drivers/staging/rtl8712/hal_init.c
Expand Up @@ -29,21 +29,31 @@
#define FWBUFF_ALIGN_SZ 512
#define MAX_DUMP_FWSZ (48 * 1024)

static void rtl871x_load_fw_fail(struct _adapter *adapter)
{
struct usb_device *udev = adapter->dvobjpriv.pusbdev;
struct device *dev = &udev->dev;
struct device *parent = dev->parent;

complete(&adapter->rtl8712_fw_ready);

dev_err(&udev->dev, "r8712u: Firmware request failed\n");

if (parent)
device_lock(parent);

device_release_driver(dev);

if (parent)
device_unlock(parent);
}

static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
{
struct _adapter *adapter = context;

if (!firmware) {
struct usb_device *udev = adapter->dvobjpriv.pusbdev;
struct usb_interface *usb_intf = adapter->pusb_intf;

dev_err(&udev->dev, "r8712u: Firmware request failed\n");
usb_put_dev(udev);
usb_set_intfdata(usb_intf, NULL);
r8712_free_drv_sw(adapter);
adapter->dvobj_deinit(adapter);
complete(&adapter->rtl8712_fw_ready);
free_netdev(adapter->pnetdev);
rtl871x_load_fw_fail(adapter);
return;
}
adapter->fw = firmware;
Expand Down
52 changes: 23 additions & 29 deletions drivers/staging/rtl8712/usb_intf.c
Expand Up @@ -594,36 +594,30 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
{
struct net_device *pnetdev = usb_get_intfdata(pusb_intf);
struct usb_device *udev = interface_to_usbdev(pusb_intf);
struct _adapter *padapter = netdev_priv(pnetdev);

/* never exit with a firmware callback pending */
wait_for_completion(&padapter->rtl8712_fw_ready);
usb_set_intfdata(pusb_intf, NULL);
release_firmware(padapter->fw);
if (drvpriv.drv_registered)
padapter->surprise_removed = true;
if (pnetdev->reg_state != NETREG_UNINITIALIZED)
unregister_netdev(pnetdev); /* will call netdev_close() */
r8712_flush_rwctrl_works(padapter);
r8712_flush_led_works(padapter);
udelay(1);
/* Stop driver mlme relation timer */
r8712_stop_drv_timers(padapter);
r871x_dev_unload(padapter);
r8712_free_drv_sw(padapter);
free_netdev(pnetdev);

/* decrease the reference count of the usb device structure
* when disconnect
*/
usb_put_dev(udev);

if (pnetdev) {
struct _adapter *padapter = netdev_priv(pnetdev);

/* 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;
if (pnetdev->reg_state != NETREG_UNINITIALIZED)
unregister_netdev(pnetdev); /* will call netdev_close() */
r8712_flush_rwctrl_works(padapter);
r8712_flush_led_works(padapter);
udelay(1);
/* Stop driver mlme relation timer */
r8712_stop_drv_timers(padapter);
r871x_dev_unload(padapter);
r8712_free_drv_sw(padapter);
free_netdev(pnetdev);

/* decrease the reference count of the usb device structure
* when disconnect
*/
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.
Expand Down

0 comments on commit 9f57b94

Please sign in to comment.