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 | if (ret < 0) { | 2873 | if (ret < 0) { |
| 2874 | netdev_warn(dev->net, | 2874 | netdev_warn(dev->net, |
| 2875 | "lan78xx_setup_irq_domain() failed : %d", ret); | 2875 | "lan78xx_setup_irq_domain() failed : %d", ret); |
| 2876 | kfree(pdata); | 2876 | goto out1; |
| 2877 | return ret; | ||
| 2878 | } | 2877 | } |
| 2879 | 2878 | ||
| 2880 | dev->net->hard_header_len += TX_OVERHEAD; | 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 | /* Init all registers */ | 2882 | /* Init all registers */ |
| 2884 | ret = lan78xx_reset(dev); | 2883 | ret = lan78xx_reset(dev); |
| 2884 | if (ret) { | ||
| 2885 | netdev_warn(dev->net, "Registers INIT FAILED...."); | ||
| 2886 | goto out2; | ||
| 2887 | } | ||
| 2885 | 2888 | ||
| 2886 | ret = lan78xx_mdio_init(dev); | 2889 | ret = lan78xx_mdio_init(dev); |
| 2890 | if (ret) { | ||
| 2891 | netdev_warn(dev->net, "MDIO INIT FAILED....."); | ||
| 2892 | goto out2; | ||
| 2893 | } | ||
| 2887 | 2894 | ||
| 2888 | dev->net->flags |= IFF_MULTICAST; | 2895 | dev->net->flags |= IFF_MULTICAST; |
| 2889 | 2896 | ||
| 2890 | pdata->wol = WAKE_MAGIC; | 2897 | pdata->wol = WAKE_MAGIC; |
| 2891 | 2898 | ||
| 2892 | return ret; | 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 | static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) | 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 | lan78xx_remove_mdio(dev); | 2918 | lan78xx_remove_mdio(dev); |
| 2902 | 2919 | ||
| 2903 | if (pdata) { | 2920 | if (pdata) { |
| 2921 | cancel_work_sync(&pdata->set_multicast); | ||
| 2922 | cancel_work_sync(&pdata->set_vlan); | ||
| 2904 | netif_dbg(dev, ifdown, dev->net, "free pdata"); | 2923 | netif_dbg(dev, ifdown, dev->net, "free pdata"); |
| 2905 | kfree(pdata); | 2924 | kfree(pdata); |
| 2906 | pdata = NULL; | 2925 | pdata = NULL; |