staging: rtl8712: fix error handling
cover staging: rtl8712: fix error handling
Hi, rtl8712 developers and stanging maintainers!
In this patch series I rewrote error handling approach in rtl8712 driver. Detailed description can be found in commit messages. In short:
There was strage approach to handle fw load error. For some reason fw callback was doing clean up stuff which can lead to UAF bug. For example:
CPU0 CPU1r871xu_dev_remove()
rtl871x_load_fw_cb()
free_netdev(netdev)wait_for_completion(netdev_priv->compl) <- UAF, slab-out-of-bound or smth else
I've added free_netdev() call in my previous patch to this driver:e02a3b945816 ("staging: rtl8712: fix memory leak in rtl871x_load_fw_cb") to avoid memory leak and I believed, that this approach won't trigger anything else, but, unfortunately, I was wrong. Syzbot found 2 bugs [1] [2] and I decided to complely rewrite error handling in case of fw load failure. This patch series was tested with both reproducers and did't trigger any bugs.
[1] https://syzkaller.appspot.com/bug?id=7646834b55c71c45ed85f601032daa6c23db0513
[2] https://syzkaller.appspot.com/bug?id=89c3ddb9936d3552995130298f1d2633ab9d3541
With regards,
Pavel Skripkin
Pavel Skripkin (2):
staging: rtl8712: get rid of flush_scheduled_work
staging: rtl8712: error handling refactoring
drivers/staging/rtl8712/hal_init.c | 30 ++++++++----- drivers/staging/rtl8712/rtl8712_led.c | 8 ++++ drivers/staging/rtl8712/rtl871x_led.h | 1 + drivers/staging/rtl8712/rtl871x_pwrctrl.c | 8 ++++ drivers/staging/rtl8712/rtl871x_pwrctrl.h | 1 + drivers/staging/rtl8712/usb_intf.c | 51 ++++++++++------------- 6 files changed, 61 insertions(+), 38 deletions(-)
Signature · 1 line
2.32.0
PATCH 1/2 staging: rtl8712: get rid of flush_scheduled_work
This patch is preparation for following patch for error handling refactoring.
flush_scheduled_work() takes (wq_completion)events lock and
it can lead to deadlock when r871xu_dev_remove() is called from workqueue. To avoid deadlock sutiation we can change flush_scheduled_work() call to flush_work() call for all possibly scheduled works in this driver, since next patch adds device_release_driver() in case of fw load failure.
--- drivers/staging/rtl8712/rtl8712_led.c | 8 ++++++++ drivers/staging/rtl8712/rtl871x_led.h | 1 + drivers/staging/rtl8712/rtl871x_pwrctrl.c | 8 ++++++++ drivers/staging/rtl8712/rtl871x_pwrctrl.h | 1 + drivers/staging/rtl8712/usb_intf.c | 3 ++- 5 files changed, 20 insertions(+), 1 deletion(-)
drivers/staging/rtl8712/rtl8712_led.c +8 -0
@@ -1820,3 +1820,11 @@ void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction)break ; } } + +void r8712_flush_led_works (struct _adapter *padapter) +{ +struct led_priv *pledpriv = &padapter->ledpriv; + +flush_work (&pledpriv->SwLed0.BlinkWorkItem); +flush_work (&pledpriv->SwLed1.BlinkWorkItem); +}
drivers/staging/rtl8712/rtl871x_led.h +1 -0
@@ -112,6 +112,7 @@ struct led_priv {void r8712_InitSwLeds (struct _adapter *padapter);void r8712_DeInitSwLeds (struct _adapter *padapter);void LedControl871x (struct _adapter *padapter,enum LED_CTL_MODE LedAction); +void r8712_flush_led_works (struct _adapter *padapter);#endif
drivers/staging/rtl8712/rtl871x_pwrctrl.c +8 -0
@@ -224,3 +224,11 @@ void r8712_unregister_cmd_alive(struct _adapter *padapter) }mutex_unlock (&pwrctrl->mutex_lock); } + +void r8712_flush_rwctrl_works (struct _adapter *padapter) +{ +struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; + +flush_work (&pwrctrl->SetPSModeWorkItem); +flush_work (&pwrctrl->rpwm_workitem); +}
drivers/staging/rtl8712/rtl871x_pwrctrl.h +1 -0
@@ -108,5 +108,6 @@ void r8712_cpwm_int_hdl(struct _adapter *padapter,void r8712_set_ps_mode (struct _adapter *padapter,uint ps_mode,uint smart_ps);void r8712_set_rpwm (struct _adapter *padapter,u8 val8); +void r8712_flush_rwctrl_works (struct _adapter *padapter);#endif /* __RTL871X_PWRCTRL_H_ */
drivers/staging/rtl8712/usb_intf.c +2 -1
@@ -606,7 +606,8 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf) padapter->surprise_removed = true;if (pnetdev->reg_state !=NETREG_UNINITIALIZED )unregister_netdev (pnetdev);/* will call netdev_close() */ -flush_scheduled_work (); +r8712_flush_rwctrl_works (padapter); +r8712_flush_led_works (padapter);udelay (1 );/* Stop driver mlme relation timer */ r8712_stop_drv_timers (padapter);
Signature · 1 line
2.32.0
PATCH 2/2 staging: rtl8712: error handling refactoring
In reply to Pavel SkripkinThere 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.
--- drivers/staging/rtl8712/hal_init.c | 30 +++++++++++------ drivers/staging/rtl8712/usb_intf.c | 52 +++++++++++++----------------- 2 files changed, 43 insertions(+), 39 deletions(-)
drivers/staging/rtl8712/hal_init.c +20 -10
@@ -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;
drivers/staging/rtl8712/usb_intf.c +23 -29
59 lines not on this page · raw message
Signature · 1 line
2.32.0