diff options
author | Sara Sharon <sara.sharon@intel.com> | 2019-10-04 08:37:06 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-10-07 15:35:57 -0400 |
commit | 461c4c2b4c0731d7452bad4e77c0cdbdcea1804c (patch) | |
tree | 17ec48a63c1aa9d72ed5c50bc1e6abc65caa3afd | |
parent | 1399c59fa92984836db90538cf92397fe7caaa57 (diff) |
cfg80211: fix a bunch of RCU issues in multi-bssid code
cfg80211_update_notlisted_nontrans() leaves the RCU critical session
too early, while still using nontrans_ssid which is RCU protected. In
addition, it performs a bunch of RCU pointer update operations such
as rcu_access_pointer and rcu_assign_pointer.
The caller, cfg80211_inform_bss_frame_data(), also accesses the RCU
pointer without holding the lock.
Just wrap all of this with bss_lock.
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/20191004123706.15768-3-luca@coelho.fi
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/wireless/scan.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ff1016607f0b..aef240fdf8df 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -1703,8 +1703,7 @@ cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy, | |||
1703 | static void | 1703 | static void |
1704 | cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, | 1704 | cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, |
1705 | struct cfg80211_bss *nontrans_bss, | 1705 | struct cfg80211_bss *nontrans_bss, |
1706 | struct ieee80211_mgmt *mgmt, size_t len, | 1706 | struct ieee80211_mgmt *mgmt, size_t len) |
1707 | gfp_t gfp) | ||
1708 | { | 1707 | { |
1709 | u8 *ie, *new_ie, *pos; | 1708 | u8 *ie, *new_ie, *pos; |
1710 | const u8 *nontrans_ssid, *trans_ssid, *mbssid; | 1709 | const u8 *nontrans_ssid, *trans_ssid, *mbssid; |
@@ -1715,6 +1714,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, | |||
1715 | const struct cfg80211_bss_ies *old; | 1714 | const struct cfg80211_bss_ies *old; |
1716 | u8 cpy_len; | 1715 | u8 cpy_len; |
1717 | 1716 | ||
1717 | lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock); | ||
1718 | |||
1718 | ie = mgmt->u.probe_resp.variable; | 1719 | ie = mgmt->u.probe_resp.variable; |
1719 | 1720 | ||
1720 | new_ie_len = ielen; | 1721 | new_ie_len = ielen; |
@@ -1731,23 +1732,22 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, | |||
1731 | if (!mbssid || mbssid < trans_ssid) | 1732 | if (!mbssid || mbssid < trans_ssid) |
1732 | return; | 1733 | return; |
1733 | new_ie_len -= mbssid[1]; | 1734 | new_ie_len -= mbssid[1]; |
1734 | rcu_read_lock(); | 1735 | |
1735 | nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); | 1736 | nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID); |
1736 | if (!nontrans_ssid) { | 1737 | if (!nontrans_ssid) |
1737 | rcu_read_unlock(); | ||
1738 | return; | 1738 | return; |
1739 | } | 1739 | |
1740 | new_ie_len += nontrans_ssid[1]; | 1740 | new_ie_len += nontrans_ssid[1]; |
1741 | rcu_read_unlock(); | ||
1742 | 1741 | ||
1743 | /* generate new ie for nontrans BSS | 1742 | /* generate new ie for nontrans BSS |
1744 | * 1. replace SSID with nontrans BSS' SSID | 1743 | * 1. replace SSID with nontrans BSS' SSID |
1745 | * 2. skip MBSSID IE | 1744 | * 2. skip MBSSID IE |
1746 | */ | 1745 | */ |
1747 | new_ie = kzalloc(new_ie_len, gfp); | 1746 | new_ie = kzalloc(new_ie_len, GFP_ATOMIC); |
1748 | if (!new_ie) | 1747 | if (!new_ie) |
1749 | return; | 1748 | return; |
1750 | new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp); | 1749 | |
1750 | new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, GFP_ATOMIC); | ||
1751 | if (!new_ies) | 1751 | if (!new_ies) |
1752 | goto out_free; | 1752 | goto out_free; |
1753 | 1753 | ||
@@ -1901,6 +1901,8 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, | |||
1901 | cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len, | 1901 | cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len, |
1902 | &non_tx_data, gfp); | 1902 | &non_tx_data, gfp); |
1903 | 1903 | ||
1904 | spin_lock_bh(&wiphy_to_rdev(wiphy)->bss_lock); | ||
1905 | |||
1904 | /* check if the res has other nontransmitting bss which is not | 1906 | /* check if the res has other nontransmitting bss which is not |
1905 | * in MBSSID IE | 1907 | * in MBSSID IE |
1906 | */ | 1908 | */ |
@@ -1915,8 +1917,9 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, | |||
1915 | ies2 = rcu_access_pointer(tmp_bss->ies); | 1917 | ies2 = rcu_access_pointer(tmp_bss->ies); |
1916 | if (ies2->tsf < ies1->tsf) | 1918 | if (ies2->tsf < ies1->tsf) |
1917 | cfg80211_update_notlisted_nontrans(wiphy, tmp_bss, | 1919 | cfg80211_update_notlisted_nontrans(wiphy, tmp_bss, |
1918 | mgmt, len, gfp); | 1920 | mgmt, len); |
1919 | } | 1921 | } |
1922 | spin_unlock_bh(&wiphy_to_rdev(wiphy)->bss_lock); | ||
1920 | 1923 | ||
1921 | return res; | 1924 | return res; |
1922 | } | 1925 | } |