Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: plfxlc: Fix error handling in usb driver probe

If probe fails before ieee80211_register_hw() is successfully done,
ieee80211_unregister_hw() will be called anyway. This may lead to various
bugs as the implementation of ieee80211_unregister_hw() assumes that
ieee80211_register_hw() has been called.

Divide error handling section into relevant subsections, so that
ieee80211_unregister_hw() is called only when it is appropriate. Correct
the order of the calls: ieee80211_unregister_hw() should go before
plfxlc_mac_release(). Also move ieee80211_free_hw() to plfxlc_mac_release()
as it supposed to be the opposite to plfxlc_mac_alloc_hw() that calls
ieee80211_alloc_hw().

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 68d57a07bfe5 ("wireless: add plfxlc driver for pureLiFi X, XL, XC devices")
Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
Link: https://patch.msgid.link/20250321185226.71-3-m.masimov@mt-integration.ru
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Murad Masimov and committed by
Johannes Berg
3fe79a25 f8bf97ad

+21 -21
+6 -5
drivers/net/wireless/purelifi/plfxlc/mac.c
··· 99 99 return r; 100 100 } 101 101 102 - void plfxlc_mac_release(struct plfxlc_mac *mac) 103 - { 104 - plfxlc_chip_release(&mac->chip); 105 - } 106 - 107 102 int plfxlc_op_start(struct ieee80211_hw *hw) 108 103 { 109 104 plfxlc_hw_mac(hw)->chip.usb.initialized = 1; ··· 750 755 751 756 SET_IEEE80211_DEV(hw, &intf->dev); 752 757 return hw; 758 + } 759 + 760 + void plfxlc_mac_release_hw(struct ieee80211_hw *hw) 761 + { 762 + plfxlc_chip_release(&plfxlc_hw_mac(hw)->chip); 763 + ieee80211_free_hw(hw); 753 764 }
+1 -1
drivers/net/wireless/purelifi/plfxlc/mac.h
··· 168 168 } 169 169 170 170 struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf); 171 - void plfxlc_mac_release(struct plfxlc_mac *mac); 171 + void plfxlc_mac_release_hw(struct ieee80211_hw *hw); 172 172 173 173 int plfxlc_mac_preinit_hw(struct ieee80211_hw *hw, const u8 *hw_address); 174 174 int plfxlc_mac_init_hw(struct ieee80211_hw *hw);
+14 -15
drivers/net/wireless/purelifi/plfxlc/usb.c
··· 604 604 r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number); 605 605 if (r) { 606 606 dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r); 607 - goto error; 607 + goto error_free_hw; 608 608 } 609 609 610 610 chip->unit_type = STA; ··· 613 613 r = plfxlc_mac_preinit_hw(hw, hw_address); 614 614 if (r) { 615 615 dev_err(&intf->dev, "Init mac failed (%d)\n", r); 616 - goto error; 616 + goto error_free_hw; 617 617 } 618 618 619 619 r = ieee80211_register_hw(hw); 620 620 if (r) { 621 621 dev_err(&intf->dev, "Register device failed (%d)\n", r); 622 - goto error; 622 + goto error_free_hw; 623 623 } 624 624 625 625 if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) == ··· 632 632 } 633 633 if (r != 0) { 634 634 dev_err(&intf->dev, "FPGA download failed (%d)\n", r); 635 - goto error; 635 + goto error_unreg_hw; 636 636 } 637 637 638 638 tx->mac_fifo_full = 0; ··· 642 642 r = plfxlc_usb_init_hw(usb); 643 643 if (r < 0) { 644 644 dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r); 645 - goto error; 645 + goto error_unreg_hw; 646 646 } 647 647 648 648 msleep(PLF_MSLEEP_TIME); 649 649 r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON); 650 650 if (r < 0) { 651 651 dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r); 652 - goto error; 652 + goto error_unreg_hw; 653 653 } 654 654 655 655 msleep(PLF_MSLEEP_TIME); 656 656 r = plfxlc_chip_set_rate(chip, 8); 657 657 if (r < 0) { 658 658 dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r); 659 - goto error; 659 + goto error_unreg_hw; 660 660 } 661 661 662 662 msleep(PLF_MSLEEP_TIME); ··· 664 664 hw_address, ETH_ALEN, USB_REQ_MAC_WR); 665 665 if (r < 0) { 666 666 dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r); 667 - goto error; 667 + goto error_unreg_hw; 668 668 } 669 669 670 670 plfxlc_chip_enable_rxtx(chip); ··· 691 691 plfxlc_mac_init_hw(hw); 692 692 usb->initialized = true; 693 693 return 0; 694 + 695 + error_unreg_hw: 696 + ieee80211_unregister_hw(hw); 697 + error_free_hw: 698 + plfxlc_mac_release_hw(hw); 694 699 error: 695 - if (hw) { 696 - plfxlc_mac_release(plfxlc_hw_mac(hw)); 697 - ieee80211_unregister_hw(hw); 698 - ieee80211_free_hw(hw); 699 - } 700 700 dev_err(&intf->dev, "pureLifi:Device error"); 701 701 return r; 702 702 } ··· 730 730 */ 731 731 usb_reset_device(interface_to_usbdev(intf)); 732 732 733 - plfxlc_mac_release(mac); 734 - ieee80211_free_hw(hw); 733 + plfxlc_mac_release_hw(hw); 735 734 } 736 735 737 736 static void plfxlc_usb_resume(struct plfxlc_usb *usb)