aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-14 11:10:24 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:49:26 -0400
commitd4e46a3d9869563c6210b01bb651c40cbe65da80 (patch)
treed37626d8077c0eaca35ec41e705c62af2a324847
parentc29b9b9b0235d56e5602f61ed38702dd376aae20 (diff)
[MAC80211]: fix race conditions with keys
During receive processing, we select the key long before using it and because there's no locking it is possible that we kfree() the key after having selected it but before using it for crypto operations. Obviously, this is bad. Secondly, during transmit processing, there are two possible races: We have a similar race between select_key() and using it for encryption, but we also have a race here between select_key() and hardware encryption (both when a key is removed.) This patch solves these issues by using RCU: when a key is to be freed, we first remove the pointer from the appropriate places (sdata->keys, sdata->default_key, sta->key) using rcu_assign_pointer() and then synchronize_rcu(). Then, we can safely kfree() the key and remove it from the hardware. There's a window here where the hardware may still be using it for decryption, but we can't work around that without having two hardware callbacks, one to disable the key for RX and one to disable it for TX; but the worst thing that will happen is that we receive a packet decrypted that we don't find a key for any more and then drop it. When we add a key, we first need to upload it to the hardware and then, using rcu_assign_pointer() again, link it into our structures. In the code using keys (TX/RX paths) we use rcu_dereference() to get the key and enclose the whole tx/rx section in a rcu_read_lock() ... rcu_read_unlock() block. Because we've uploaded the key to hardware before linking it into internal structures, we can guarantee that it is valid once get to into tx(). One possible race condition remains, however: when we have hardware acceleration enabled and the driver shuts down the queues, we end up queueing the frame. If now somebody removes the key, the key will be removed from hwaccel and then then driver will be asked to encrypt the frame with a key index that has been removed. Hence, drivers will need to be aware that the hw_key_index they are passed might not be under all circumstances. Most drivers will, however, simply ignore that condition and encrypt the frame with the selected key anyway, this only results in a frame being encrypted with a wrong key or dropped (rightfully) because the key was not valid. There isn't much we can do about it unless we want to walk the pending frame queue every time a key is removed and remove all frames that used it. This race condition, however, will most likely be solved once we add multiqueue support to mac80211 because then frames will be queued further up the stack instead of after being processed. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/mac80211/ieee80211_ioctl.c5
-rw-r--r--net/mac80211/key.c43
-rw-r--r--net/mac80211/rx.c20
-rw-r--r--net/mac80211/tx.c20
4 files changed, 61 insertions, 27 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 1d585cc2c8c7..10ec05624a67 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -73,11 +73,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
73 key = NULL; 73 key = NULL;
74 } else { 74 } else {
75 /* 75 /*
76 * Need to free it before allocating a new one with 76 * Automatically frees any old key if present.
77 * with the same index or the ordering to the driver's
78 * set_key() callback becomes confused.
79 */ 77 */
80 ieee80211_key_free(key);
81 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); 78 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
82 if (!key) { 79 if (!key) {
83 ret = -ENOMEM; 80 ret = -ENOMEM;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 178f00cf61b9..19e77f626d84 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -12,6 +12,7 @@
12#include <linux/if_ether.h> 12#include <linux/if_ether.h>
13#include <linux/etherdevice.h> 13#include <linux/etherdevice.h>
14#include <linux/list.h> 14#include <linux/list.h>
15#include <linux/rcupdate.h>
15#include <net/mac80211.h> 16#include <net/mac80211.h>
16#include "ieee80211_i.h" 17#include "ieee80211_i.h"
17#include "debugfs_key.h" 18#include "debugfs_key.h"
@@ -120,6 +121,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
120{ 121{
121 struct ieee80211_key *key; 122 struct ieee80211_key *key;
122 123
124 BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS);
123 BUG_ON(alg == ALG_NONE); 125 BUG_ON(alg == ALG_NONE);
124 126
125 key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); 127 key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
@@ -157,9 +159,15 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
157 159
158 ieee80211_debugfs_key_add(key->local, key); 160 ieee80211_debugfs_key_add(key->local, key);
159 161
162 /* remove key first */
163 if (sta)
164 ieee80211_key_free(sta->key);
165 else
166 ieee80211_key_free(sdata->keys[idx]);
167
160 if (sta) { 168 if (sta) {
161 ieee80211_debugfs_key_sta_link(key, sta); 169 ieee80211_debugfs_key_sta_link(key, sta);
162 sta->key = key; 170
163 /* 171 /*
164 * some hardware cannot handle TKIP with QoS, so 172 * some hardware cannot handle TKIP with QoS, so
165 * we indicate whether QoS could be in use. 173 * we indicate whether QoS could be in use.
@@ -179,21 +187,19 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
179 sta_info_put(ap); 187 sta_info_put(ap);
180 } 188 }
181 } 189 }
182
183 if (idx >= 0 && idx < NUM_DEFAULT_KEYS) {
184 if (!sdata->keys[idx])
185 sdata->keys[idx] = key;
186 else
187 WARN_ON(1);
188 } else
189 WARN_ON(1);
190 } 190 }
191 191
192 list_add(&key->list, &sdata->key_list); 192 /* enable hwaccel if appropriate */
193
194 if (netif_running(key->sdata->dev)) 193 if (netif_running(key->sdata->dev))
195 ieee80211_key_enable_hw_accel(key); 194 ieee80211_key_enable_hw_accel(key);
196 195
196 if (sta)
197 rcu_assign_pointer(sta->key, key);
198 else
199 rcu_assign_pointer(sdata->keys[idx], key);
200
201 list_add(&key->list, &sdata->key_list);
202
197 return key; 203 return key;
198} 204}
199 205
@@ -202,20 +208,25 @@ void ieee80211_key_free(struct ieee80211_key *key)
202 if (!key) 208 if (!key)
203 return; 209 return;
204 210
205 ieee80211_key_disable_hw_accel(key);
206
207 if (key->sta) { 211 if (key->sta) {
208 key->sta->key = NULL; 212 rcu_assign_pointer(key->sta->key, NULL);
209 } else { 213 } else {
210 if (key->sdata->default_key == key) 214 if (key->sdata->default_key == key)
211 ieee80211_set_default_key(key->sdata, -1); 215 ieee80211_set_default_key(key->sdata, -1);
212 if (key->conf.keyidx >= 0 && 216 if (key->conf.keyidx >= 0 &&
213 key->conf.keyidx < NUM_DEFAULT_KEYS) 217 key->conf.keyidx < NUM_DEFAULT_KEYS)
214 key->sdata->keys[key->conf.keyidx] = NULL; 218 rcu_assign_pointer(key->sdata->keys[key->conf.keyidx],
219 NULL);
215 else 220 else
216 WARN_ON(1); 221 WARN_ON(1);
217 } 222 }
218 223
224 /* wait for all key users to complete */
225 synchronize_rcu();
226
227 /* remove from hwaccel if appropriate */
228 ieee80211_key_disable_hw_accel(key);
229
219 if (key->conf.alg == ALG_CCMP) 230 if (key->conf.alg == ALG_CCMP)
220 ieee80211_aes_key_free(key->u.ccmp.tfm); 231 ieee80211_aes_key_free(key->u.ccmp.tfm);
221 ieee80211_debugfs_key_remove(key); 232 ieee80211_debugfs_key_remove(key);
@@ -235,7 +246,7 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
235 if (sdata->default_key != key) { 246 if (sdata->default_key != key) {
236 ieee80211_debugfs_key_remove_default(sdata); 247 ieee80211_debugfs_key_remove_default(sdata);
237 248
238 sdata->default_key = key; 249 rcu_assign_pointer(sdata->default_key, key);
239 250
240 if (sdata->default_key) 251 if (sdata->default_key)
241 ieee80211_debugfs_key_add_default(sdata); 252 ieee80211_debugfs_key_add_default(sdata);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4fb8c7026f11..91b7886bf797 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -13,6 +13,7 @@
13#include <linux/skbuff.h> 13#include <linux/skbuff.h>
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/etherdevice.h> 15#include <linux/etherdevice.h>
16#include <linux/rcupdate.h>
16#include <net/mac80211.h> 17#include <net/mac80211.h>
17#include <net/ieee80211_radiotap.h> 18#include <net/ieee80211_radiotap.h>
18 19
@@ -311,6 +312,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
311 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; 312 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
312 int keyidx; 313 int keyidx;
313 int hdrlen; 314 int hdrlen;
315 struct ieee80211_key *stakey = NULL;
314 316
315 /* 317 /*
316 * Key selection 101 318 * Key selection 101
@@ -348,8 +350,11 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
348 if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) 350 if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
349 return TXRX_CONTINUE; 351 return TXRX_CONTINUE;
350 352
351 if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) { 353 if (rx->sta)
352 rx->key = rx->sta->key; 354 stakey = rcu_dereference(rx->sta->key);
355
356 if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
357 rx->key = stakey;
353 } else { 358 } else {
354 /* 359 /*
355 * The device doesn't give us the IV so we won't be 360 * The device doesn't give us the IV so we won't be
@@ -374,7 +379,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
374 */ 379 */
375 keyidx = rx->skb->data[hdrlen + 3] >> 6; 380 keyidx = rx->skb->data[hdrlen + 3] >> 6;
376 381
377 rx->key = rx->sdata->keys[keyidx]; 382 rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
378 383
379 /* 384 /*
380 * RSNA-protected unicast frames should always be sent with 385 * RSNA-protected unicast frames should always be sent with
@@ -1364,6 +1369,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1364 skb_pull(skb, radiotap_len); 1369 skb_pull(skb, radiotap_len);
1365 } 1370 }
1366 1371
1372 /*
1373 * key references are protected using RCU and this requires that
1374 * we are in a read-site RCU section during receive processing
1375 */
1376 rcu_read_lock();
1377
1367 hdr = (struct ieee80211_hdr *) skb->data; 1378 hdr = (struct ieee80211_hdr *) skb->data;
1368 memset(&rx, 0, sizeof(rx)); 1379 memset(&rx, 0, sizeof(rx));
1369 rx.skb = skb; 1380 rx.skb = skb;
@@ -1404,6 +1415,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1404 ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, 1415 ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
1405 rx.sta); 1416 rx.sta);
1406 sta_info_put(sta); 1417 sta_info_put(sta);
1418 rcu_read_unlock();
1407 return; 1419 return;
1408 } 1420 }
1409 1421
@@ -1465,6 +1477,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1465 read_unlock(&local->sub_if_lock); 1477 read_unlock(&local->sub_if_lock);
1466 1478
1467 end: 1479 end:
1480 rcu_read_unlock();
1481
1468 if (sta) 1482 if (sta)
1469 sta_info_put(sta); 1483 sta_info_put(sta);
1470} 1484}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0820f127da2b..b29dc70b2f01 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -17,6 +17,7 @@
17#include <linux/skbuff.h> 17#include <linux/skbuff.h>
18#include <linux/etherdevice.h> 18#include <linux/etherdevice.h>
19#include <linux/bitmap.h> 19#include <linux/bitmap.h>
20#include <linux/rcupdate.h>
20#include <net/net_namespace.h> 21#include <net/net_namespace.h>
21#include <net/ieee80211_radiotap.h> 22#include <net/ieee80211_radiotap.h>
22#include <net/cfg80211.h> 23#include <net/cfg80211.h>
@@ -427,14 +428,16 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
427static ieee80211_txrx_result 428static ieee80211_txrx_result
428ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) 429ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
429{ 430{
431 struct ieee80211_key *key;
432
430 tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; 433 tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
431 434
432 if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) 435 if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
433 tx->key = NULL; 436 tx->key = NULL;
434 else if (tx->sta && tx->sta->key) 437 else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
435 tx->key = tx->sta->key; 438 tx->key = key;
436 else if (tx->sdata->default_key) 439 else if ((key = rcu_dereference(tx->sdata->default_key)))
437 tx->key = tx->sdata->default_key; 440 tx->key = key;
438 else if (tx->sdata->drop_unencrypted && 441 else if (tx->sdata->drop_unencrypted &&
439 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { 442 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
440 I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); 443 I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
@@ -1112,6 +1115,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
1112 return 0; 1115 return 0;
1113 } 1116 }
1114 1117
1118 /*
1119 * key references are protected using RCU and this requires that
1120 * we are in a read-site RCU section during receive processing
1121 */
1122 rcu_read_lock();
1123
1115 sta = tx.sta; 1124 sta = tx.sta;
1116 tx.u.tx.mgmt_interface = mgmt; 1125 tx.u.tx.mgmt_interface = mgmt;
1117 tx.u.tx.mode = local->hw.conf.mode; 1126 tx.u.tx.mode = local->hw.conf.mode;
@@ -1139,6 +1148,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
1139 1148
1140 if (unlikely(res == TXRX_QUEUED)) { 1149 if (unlikely(res == TXRX_QUEUED)) {
1141 I802_DEBUG_INC(local->tx_handlers_queued); 1150 I802_DEBUG_INC(local->tx_handlers_queued);
1151 rcu_read_unlock();
1142 return 0; 1152 return 0;
1143 } 1153 }
1144 1154
@@ -1196,6 +1206,7 @@ retry:
1196 store->last_frag_rate_ctrl_probe = 1206 store->last_frag_rate_ctrl_probe =
1197 !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); 1207 !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
1198 } 1208 }
1209 rcu_read_unlock();
1199 return 0; 1210 return 0;
1200 1211
1201 drop: 1212 drop:
@@ -1205,6 +1216,7 @@ retry:
1205 if (tx.u.tx.extra_frag[i]) 1216 if (tx.u.tx.extra_frag[i])
1206 dev_kfree_skb(tx.u.tx.extra_frag[i]); 1217 dev_kfree_skb(tx.u.tx.extra_frag[i]);
1207 kfree(tx.u.tx.extra_frag); 1218 kfree(tx.u.tx.extra_frag);
1219 rcu_read_unlock();
1208 return 0; 1220 return 0;
1209} 1221}
1210 1222