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

Merge tag 'mac80211-for-net-2021-10-27' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
Two fixes:
* bridge vs. 4-addr mode check was wrong
* management frame registrations locking was
wrong, causing list corruption/crashes
====================

Link: https://lore.kernel.org/r/20211027143756.91711-1-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+24 -22
-2
include/net/cfg80211.h
··· 5376 5376 * netdev and may otherwise be used by driver read-only, will be update 5377 5377 * by cfg80211 on change_interface 5378 5378 * @mgmt_registrations: list of registrations for management frames 5379 - * @mgmt_registrations_lock: lock for the list 5380 5379 * @mgmt_registrations_need_update: mgmt registrations were updated, 5381 5380 * need to propagate the update to the driver 5382 5381 * @mtx: mutex used to lock data in this struct, may be used by drivers ··· 5422 5423 u32 identifier; 5423 5424 5424 5425 struct list_head mgmt_registrations; 5425 - spinlock_t mgmt_registrations_lock; 5426 5426 u8 mgmt_registrations_need_update:1; 5427 5427 5428 5428 struct mutex mtx;
+1 -1
net/wireless/core.c
··· 524 524 INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk); 525 525 INIT_WORK(&rdev->mgmt_registrations_update_wk, 526 526 cfg80211_mgmt_registrations_update_wk); 527 + spin_lock_init(&rdev->mgmt_registrations_lock); 527 528 528 529 #ifdef CONFIG_CFG80211_DEFAULT_PS 529 530 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ··· 1280 1279 INIT_LIST_HEAD(&wdev->event_list); 1281 1280 spin_lock_init(&wdev->event_lock); 1282 1281 INIT_LIST_HEAD(&wdev->mgmt_registrations); 1283 - spin_lock_init(&wdev->mgmt_registrations_lock); 1284 1282 INIT_LIST_HEAD(&wdev->pmsr_list); 1285 1283 spin_lock_init(&wdev->pmsr_lock); 1286 1284 INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
+2
net/wireless/core.h
··· 100 100 struct work_struct propagate_cac_done_wk; 101 101 102 102 struct work_struct mgmt_registrations_update_wk; 103 + /* lock for all wdev lists */ 104 + spinlock_t mgmt_registrations_lock; 103 105 104 106 /* must be last because of the way we do wiphy_priv(), 105 107 * and it should at least be aligned to NETDEV_ALIGN */
+14 -12
net/wireless/mlme.c
··· 452 452 453 453 lockdep_assert_held(&rdev->wiphy.mtx); 454 454 455 - spin_lock_bh(&wdev->mgmt_registrations_lock); 455 + spin_lock_bh(&rdev->mgmt_registrations_lock); 456 456 if (!wdev->mgmt_registrations_need_update) { 457 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 457 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 458 458 return; 459 459 } 460 460 ··· 479 479 rcu_read_unlock(); 480 480 481 481 wdev->mgmt_registrations_need_update = 0; 482 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 482 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 483 483 484 484 rdev_update_mgmt_frame_registrations(rdev, wdev, &upd); 485 485 } ··· 503 503 int match_len, bool multicast_rx, 504 504 struct netlink_ext_ack *extack) 505 505 { 506 + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 506 507 struct cfg80211_mgmt_registration *reg, *nreg; 507 508 int err = 0; 508 509 u16 mgmt_type; ··· 549 548 if (!nreg) 550 549 return -ENOMEM; 551 550 552 - spin_lock_bh(&wdev->mgmt_registrations_lock); 551 + spin_lock_bh(&rdev->mgmt_registrations_lock); 553 552 554 553 list_for_each_entry(reg, &wdev->mgmt_registrations, list) { 555 554 int mlen = min(match_len, reg->match_len); ··· 584 583 list_add(&nreg->list, &wdev->mgmt_registrations); 585 584 } 586 585 wdev->mgmt_registrations_need_update = 1; 587 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 586 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 588 587 589 588 cfg80211_mgmt_registrations_update(wdev); 590 589 ··· 592 591 593 592 out: 594 593 kfree(nreg); 595 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 594 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 596 595 597 596 return err; 598 597 } ··· 603 602 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); 604 603 struct cfg80211_mgmt_registration *reg, *tmp; 605 604 606 - spin_lock_bh(&wdev->mgmt_registrations_lock); 605 + spin_lock_bh(&rdev->mgmt_registrations_lock); 607 606 608 607 list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { 609 608 if (reg->nlportid != nlportid) ··· 616 615 schedule_work(&rdev->mgmt_registrations_update_wk); 617 616 } 618 617 619 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 618 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 620 619 621 620 if (nlportid && rdev->crit_proto_nlportid == nlportid) { 622 621 rdev->crit_proto_nlportid = 0; ··· 629 628 630 629 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) 631 630 { 631 + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 632 632 struct cfg80211_mgmt_registration *reg, *tmp; 633 633 634 - spin_lock_bh(&wdev->mgmt_registrations_lock); 634 + spin_lock_bh(&rdev->mgmt_registrations_lock); 635 635 list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { 636 636 list_del(&reg->list); 637 637 kfree(reg); 638 638 } 639 639 wdev->mgmt_registrations_need_update = 1; 640 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 640 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 641 641 642 642 cfg80211_mgmt_registrations_update(wdev); 643 643 } ··· 786 784 data = buf + ieee80211_hdrlen(mgmt->frame_control); 787 785 data_len = len - ieee80211_hdrlen(mgmt->frame_control); 788 786 789 - spin_lock_bh(&wdev->mgmt_registrations_lock); 787 + spin_lock_bh(&rdev->mgmt_registrations_lock); 790 788 791 789 list_for_each_entry(reg, &wdev->mgmt_registrations, list) { 792 790 if (reg->frame_type != ftype) ··· 810 808 break; 811 809 } 812 810 813 - spin_unlock_bh(&wdev->mgmt_registrations_lock); 811 + spin_unlock_bh(&rdev->mgmt_registrations_lock); 814 812 815 813 trace_cfg80211_return_bool(result); 816 814 return result;
+7 -7
net/wireless/util.c
··· 1028 1028 !(rdev->wiphy.interface_modes & (1 << ntype))) 1029 1029 return -EOPNOTSUPP; 1030 1030 1031 - /* if it's part of a bridge, reject changing type to station/ibss */ 1032 - if (netif_is_bridge_port(dev) && 1033 - (ntype == NL80211_IFTYPE_ADHOC || 1034 - ntype == NL80211_IFTYPE_STATION || 1035 - ntype == NL80211_IFTYPE_P2P_CLIENT)) 1036 - return -EBUSY; 1037 - 1038 1031 if (ntype != otype) { 1032 + /* if it's part of a bridge, reject changing type to station/ibss */ 1033 + if (netif_is_bridge_port(dev) && 1034 + (ntype == NL80211_IFTYPE_ADHOC || 1035 + ntype == NL80211_IFTYPE_STATION || 1036 + ntype == NL80211_IFTYPE_P2P_CLIENT)) 1037 + return -EBUSY; 1038 + 1039 1039 dev->ieee80211_ptr->use_4addr = false; 1040 1040 dev->ieee80211_ptr->mesh_id_up_len = 0; 1041 1041 wdev_lock(dev->ieee80211_ptr);