From: Pavel Skripkin paskripkin@gmail.com
[ Upstream commit e02a3b945816a77702a2769a70ef5f9b06e49d54 ]
There is a leak in rtl8712 driver. The problem was in non-freed adapter data if firmware load failed.
This leak can be reproduced with this code: https://syzkaller.appspot.com/text?tag=ReproC&x=16612f02d00000, Autoload must fail (to not hit memory leak reported by syzkaller)
There are 2 possible ways how rtl871x_load_fw_cb() and r871xu_dev_remove() can be called (in case of fw load error).
1st case: r871xu_dev_remove() then rtl871x_load_fw_cb()
In this case r871xu_dev_remove() will wait for completion and then will jump to the end, because rtl871x_load_fw_cb() set intfdata to NULL:
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;
... clean up code here ... }
2nd case: rtl871x_load_fw_cb() then r871xu_dev_remove()
In this case pnetdev (from code snippet above) will be zero (because rtl871x_load_fw_cb() set it to NULL) And clean up code won't be executed again.
So, in all cases we need to free adapted data in rtl871x_load_fw_cb(), because disconnect function cannot take care of it. And there won't be any race conditions, because complete() call happens after setting intfdata to NULL.
In previous patch I moved out free_netdev() from r8712_free_drv_sw() and that's why now it's possible to free adapter data and then call complete.
Fixes: 8c213fa59199 ("staging: r8712u: Use asynchronous firmware loading") Signed-off-by: Pavel Skripkin paskripkin@gmail.com Link: https://lore.kernel.org/r/81e68fe0194499cc2e7692d35bc4dcf167827d8f.162362063... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/staging/rtl8712/hal_init.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c index 715f1fe8b472..22974277afa0 100644 --- a/drivers/staging/rtl8712/hal_init.c +++ b/drivers/staging/rtl8712/hal_init.c @@ -40,7 +40,10 @@ 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); + r8712_free_drv_sw(adapter); + adapter->dvobj_deinit(adapter); complete(&adapter->rtl8712_fw_ready); + free_netdev(adapter->pnetdev); return; } adapter->fw = firmware;