Description: Crash was reported with syzkaller pointing to lan78xx_write_reg routine. Root-cause: Proper cleanup of workqueues and init/setup routines was not happening in failure conditions. Fix: Handled the error conditions by cleaning up the queues and init/setup routines.
Unified · Split
| @@ -2873,8 +2873,7 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) · 2872 unmodified lines | ||
| 2873 | 2873 | if (ret < 0) { |
| 2874 | 2874 | netdev_warn(dev->net, |
| 2875 | 2875 | "lan78xx_setup_irq_domain() failed : %d", ret); |
| 2876 | − kfree(pdata); | |
| 2877 | − return ret; | |
| 2876 | + goto out1; | |
| 2878 | 2877 | } |
| 2879 | 2878 | |
| 2880 | 2879 | dev->net->hard_header_len += TX_OVERHEAD; |
| @@ -2882,14 +2881,32 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) · 1 unmodified line | ||
| 2882 | 2881 | |
| 2883 | 2882 | /* Init all registers */ |
| 2884 | 2883 | ret = lan78xx_reset(dev); |
| 2884 | + if (ret) { | |
| 2885 | + netdev_warn(dev->net, "Registers INIT FAILED...."); | |
| 2886 | + goto out2; | |
| 2887 | + } | |
| 2885 | 2888 | |
| 2886 | 2889 | ret = lan78xx_mdio_init(dev); |
| 2890 | + if (ret) { | |
| 2891 | + netdev_warn(dev->net, "MDIO INIT FAILED....."); | |
| 2892 | + goto out2; | |
| 2893 | + } | |
| 2887 | 2894 | |
| 2888 | 2895 | dev->net->flags |= IFF_MULTICAST; |
| 2889 | 2896 | |
| 2890 | 2897 | pdata->wol = WAKE_MAGIC; |
| 2891 | 2898 | |
| 2892 | 2899 | return ret; |
| 2900 | + | |
| 2901 | +out2: | |
| 2902 | + lan78xx_remove_irq_domain(dev); | |
| 2903 | + | |
| 2904 | +out1: | |
| 2905 | + netdev_warn(dev->net, "Bind routine FAILED"); | |
| 2906 | + cancel_work_sync(&pdata->set_multicast); | |
| 2907 | + cancel_work_sync(&pdata->set_vlan); | |
| 2908 | + kfree(pdata); | |
| 2909 | + return ret; | |
| 2893 | 2910 | } |
| 2894 | 2911 | |
| 2895 | 2912 | static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) |
| @@ -2901,6 +2918,8 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) · 5 unmodified lines | ||
| 2901 | 2918 | lan78xx_remove_mdio(dev); |
| 2902 | 2919 | |
| 2903 | 2920 | if (pdata) { |
| 2921 | + cancel_work_sync(&pdata->set_multicast); | |
| 2922 | + cancel_work_sync(&pdata->set_vlan); | |
| 2904 | 2923 | netif_dbg(dev, ifdown, dev->net, "free pdata"); |
| 2905 | 2924 | kfree(pdata); |
| 2906 | 2925 | pdata = NULL; |