aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@qca.qualcomm.com>2011-11-28 16:47:15 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-30 14:16:31 -0500
commita042994dd377d86bff9446ee76151ceb6267c9ba (patch)
tree2e7a30ca3f6ce9ecb06179abce92bc9520981506 /net/wireless/reg.c
parent2a1e0fd175dcfd72096ba9291d31e3b1b5342e60 (diff)
cfg80211: fix race on init and driver registration
There is a theoretical race that if hit will trigger a crash. The race is between when we issue the first regulatory hint, regulatory_hint_core(), gets processed by the workqueue and between when the first device gets registered to the wireless core. This is not easy to reproduce but it was easy to do so through the regulatory simulator I have been working on. This is a port of the fix I implemented there [1]. [1] https://github.com/mcgrof/regsim/commit/a246ccf81f059cb662eee288aa13100f631e4cc8 Cc: stable@vger.kernel.org Cc: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c43
1 files changed, 27 insertions, 16 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 186b7f2a27b6..0ec40715a67b 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -55,8 +55,17 @@
55#define REG_DBG_PRINT(args...) 55#define REG_DBG_PRINT(args...)
56#endif 56#endif
57 57
58static struct regulatory_request core_request_world = {
59 .initiator = NL80211_REGDOM_SET_BY_CORE,
60 .alpha2[0] = '0',
61 .alpha2[1] = '0',
62 .intersect = false,
63 .processed = true,
64 .country_ie_env = ENVIRON_ANY,
65};
66
58/* Receipt of information from last regulatory request */ 67/* Receipt of information from last regulatory request */
59static struct regulatory_request *last_request; 68static struct regulatory_request *last_request = &core_request_world;
60 69
61/* To trigger userspace events */ 70/* To trigger userspace events */
62static struct platform_device *reg_pdev; 71static struct platform_device *reg_pdev;
@@ -148,7 +157,7 @@ static char user_alpha2[2];
148module_param(ieee80211_regdom, charp, 0444); 157module_param(ieee80211_regdom, charp, 0444);
149MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); 158MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
150 159
151static void reset_regdomains(void) 160static void reset_regdomains(bool full_reset)
152{ 161{
153 /* avoid freeing static information or freeing something twice */ 162 /* avoid freeing static information or freeing something twice */
154 if (cfg80211_regdomain == cfg80211_world_regdom) 163 if (cfg80211_regdomain == cfg80211_world_regdom)
@@ -163,6 +172,13 @@ static void reset_regdomains(void)
163 172
164 cfg80211_world_regdom = &world_regdom; 173 cfg80211_world_regdom = &world_regdom;
165 cfg80211_regdomain = NULL; 174 cfg80211_regdomain = NULL;
175
176 if (!full_reset)
177 return;
178
179 if (last_request != &core_request_world)
180 kfree(last_request);
181 last_request = &core_request_world;
166} 182}
167 183
168/* 184/*
@@ -173,7 +189,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd)
173{ 189{
174 BUG_ON(!last_request); 190 BUG_ON(!last_request);
175 191
176 reset_regdomains(); 192 reset_regdomains(false);
177 193
178 cfg80211_world_regdom = rd; 194 cfg80211_world_regdom = rd;
179 cfg80211_regdomain = rd; 195 cfg80211_regdomain = rd;
@@ -1405,7 +1421,8 @@ static int __regulatory_hint(struct wiphy *wiphy,
1405 } 1421 }
1406 1422
1407new_request: 1423new_request:
1408 kfree(last_request); 1424 if (last_request != &core_request_world)
1425 kfree(last_request);
1409 1426
1410 last_request = pending_request; 1427 last_request = pending_request;
1411 last_request->intersect = intersect; 1428 last_request->intersect = intersect;
@@ -1575,9 +1592,6 @@ static int regulatory_hint_core(const char *alpha2)
1575{ 1592{
1576 struct regulatory_request *request; 1593 struct regulatory_request *request;
1577 1594
1578 kfree(last_request);
1579 last_request = NULL;
1580
1581 request = kzalloc(sizeof(struct regulatory_request), 1595 request = kzalloc(sizeof(struct regulatory_request),
1582 GFP_KERNEL); 1596 GFP_KERNEL);
1583 if (!request) 1597 if (!request)
@@ -1775,7 +1789,7 @@ static void restore_regulatory_settings(bool reset_user)
1775 mutex_lock(&cfg80211_mutex); 1789 mutex_lock(&cfg80211_mutex);
1776 mutex_lock(&reg_mutex); 1790 mutex_lock(&reg_mutex);
1777 1791
1778 reset_regdomains(); 1792 reset_regdomains(true);
1779 restore_alpha2(alpha2, reset_user); 1793 restore_alpha2(alpha2, reset_user);
1780 1794
1781 /* 1795 /*
@@ -2044,7 +2058,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2044 int r; 2058 int r;
2045 2059
2046 if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { 2060 if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
2047 reset_regdomains(); 2061 reset_regdomains(false);
2048 cfg80211_regdomain = rd; 2062 cfg80211_regdomain = rd;
2049 return 0; 2063 return 0;
2050 } 2064 }
@@ -2065,7 +2079,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2065 if (r) 2079 if (r)
2066 return r; 2080 return r;
2067 2081
2068 reset_regdomains(); 2082 reset_regdomains(false);
2069 cfg80211_regdomain = rd; 2083 cfg80211_regdomain = rd;
2070 return 0; 2084 return 0;
2071 } 2085 }
@@ -2090,7 +2104,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2090 2104
2091 rd = NULL; 2105 rd = NULL;
2092 2106
2093 reset_regdomains(); 2107 reset_regdomains(false);
2094 cfg80211_regdomain = intersected_rd; 2108 cfg80211_regdomain = intersected_rd;
2095 2109
2096 return 0; 2110 return 0;
@@ -2110,7 +2124,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2110 kfree(rd); 2124 kfree(rd);
2111 rd = NULL; 2125 rd = NULL;
2112 2126
2113 reset_regdomains(); 2127 reset_regdomains(false);
2114 cfg80211_regdomain = intersected_rd; 2128 cfg80211_regdomain = intersected_rd;
2115 2129
2116 return 0; 2130 return 0;
@@ -2263,11 +2277,8 @@ void /* __init_or_exit */ regulatory_exit(void)
2263 mutex_lock(&cfg80211_mutex); 2277 mutex_lock(&cfg80211_mutex);
2264 mutex_lock(&reg_mutex); 2278 mutex_lock(&reg_mutex);
2265 2279
2266 reset_regdomains(); 2280 reset_regdomains(true);
2267
2268 kfree(last_request);
2269 2281
2270 last_request = NULL;
2271 dev_set_uevent_suppress(&reg_pdev->dev, true); 2282 dev_set_uevent_suppress(&reg_pdev->dev, true);
2272 2283
2273 platform_device_unregister(reg_pdev); 2284 platform_device_unregister(reg_pdev);