diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-01-23 15:44:15 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:26:45 -0500 |
commit | 09552ccd8277e6382097e93a40f7311a09449367 (patch) | |
tree | c6e9b3f46ab04a0f1a461699d01cd6dbaa71e9bb /drivers/net | |
parent | 7be1bb6b798d506693d2d8668e801951996b5a4a (diff) |
b43: Drop packets that we are not able to encrypt
We must not transmit packets we're not able to encrypt.
This fixes a bug where in a tiny timeframe after machine resume
packets can get sent unencrypted and might leak information.
This also fixes three small resource leakages I spotted while fixing
the security problem. Properly deallocate the DMA slots in any DMA
allocation error path.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 30 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.h | 10 |
3 files changed, 58 insertions, 30 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3e73d2a523aa..8a708b77925d 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -1114,7 +1114,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1114 | { | 1114 | { |
1115 | const struct b43_dma_ops *ops = ring->ops; | 1115 | const struct b43_dma_ops *ops = ring->ops; |
1116 | u8 *header; | 1116 | u8 *header; |
1117 | int slot; | 1117 | int slot, old_top_slot, old_used_slots; |
1118 | int err; | 1118 | int err; |
1119 | struct b43_dmadesc_generic *desc; | 1119 | struct b43_dmadesc_generic *desc; |
1120 | struct b43_dmadesc_meta *meta; | 1120 | struct b43_dmadesc_meta *meta; |
@@ -1126,6 +1126,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1126 | #define SLOTS_PER_PACKET 2 | 1126 | #define SLOTS_PER_PACKET 2 |
1127 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); | 1127 | B43_WARN_ON(skb_shinfo(skb)->nr_frags); |
1128 | 1128 | ||
1129 | old_top_slot = ring->current_slot; | ||
1130 | old_used_slots = ring->used_slots; | ||
1131 | |||
1129 | /* Get a slot for the header. */ | 1132 | /* Get a slot for the header. */ |
1130 | slot = request_slot(ring); | 1133 | slot = request_slot(ring); |
1131 | desc = ops->idx2desc(ring, slot, &meta_hdr); | 1134 | desc = ops->idx2desc(ring, slot, &meta_hdr); |
@@ -1133,13 +1136,21 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1133 | 1136 | ||
1134 | header = &(ring->txhdr_cache[slot * hdrsize]); | 1137 | header = &(ring->txhdr_cache[slot * hdrsize]); |
1135 | cookie = generate_cookie(ring, slot); | 1138 | cookie = generate_cookie(ring, slot); |
1136 | b43_generate_txhdr(ring->dev, header, | 1139 | err = b43_generate_txhdr(ring->dev, header, |
1137 | skb->data, skb->len, ctl, cookie); | 1140 | skb->data, skb->len, ctl, cookie); |
1141 | if (unlikely(err)) { | ||
1142 | ring->current_slot = old_top_slot; | ||
1143 | ring->used_slots = old_used_slots; | ||
1144 | return err; | ||
1145 | } | ||
1138 | 1146 | ||
1139 | meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, | 1147 | meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, |
1140 | hdrsize, 1); | 1148 | hdrsize, 1); |
1141 | if (dma_mapping_error(meta_hdr->dmaaddr)) | 1149 | if (dma_mapping_error(meta_hdr->dmaaddr)) { |
1150 | ring->current_slot = old_top_slot; | ||
1151 | ring->used_slots = old_used_slots; | ||
1142 | return -EIO; | 1152 | return -EIO; |
1153 | } | ||
1143 | ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, | 1154 | ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, |
1144 | hdrsize, 1, 0, 0); | 1155 | hdrsize, 1, 0, 0); |
1145 | 1156 | ||
@@ -1157,6 +1168,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1157 | if (dma_mapping_error(meta->dmaaddr)) { | 1168 | if (dma_mapping_error(meta->dmaaddr)) { |
1158 | bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); | 1169 | bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); |
1159 | if (!bounce_skb) { | 1170 | if (!bounce_skb) { |
1171 | ring->current_slot = old_top_slot; | ||
1172 | ring->used_slots = old_used_slots; | ||
1160 | err = -ENOMEM; | 1173 | err = -ENOMEM; |
1161 | goto out_unmap_hdr; | 1174 | goto out_unmap_hdr; |
1162 | } | 1175 | } |
@@ -1167,6 +1180,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1167 | meta->skb = skb; | 1180 | meta->skb = skb; |
1168 | meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); | 1181 | meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); |
1169 | if (dma_mapping_error(meta->dmaaddr)) { | 1182 | if (dma_mapping_error(meta->dmaaddr)) { |
1183 | ring->current_slot = old_top_slot; | ||
1184 | ring->used_slots = old_used_slots; | ||
1170 | err = -EIO; | 1185 | err = -EIO; |
1171 | goto out_free_bounce; | 1186 | goto out_free_bounce; |
1172 | } | 1187 | } |
@@ -1252,6 +1267,13 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1252 | B43_WARN_ON(ring->stopped); | 1267 | B43_WARN_ON(ring->stopped); |
1253 | 1268 | ||
1254 | err = dma_tx_fragment(ring, skb, ctl); | 1269 | err = dma_tx_fragment(ring, skb, ctl); |
1270 | if (unlikely(err == -ENOKEY)) { | ||
1271 | /* Drop this packet, as we don't have the encryption key | ||
1272 | * anymore and must not transmit it unencrypted. */ | ||
1273 | dev_kfree_skb_any(skb); | ||
1274 | err = 0; | ||
1275 | goto out_unlock; | ||
1276 | } | ||
1255 | if (unlikely(err)) { | 1277 | if (unlikely(err)) { |
1256 | b43err(dev->wl, "DMA tx mapping failure\n"); | 1278 | b43err(dev->wl, "DMA tx mapping failure\n"); |
1257 | goto out_unlock; | 1279 | goto out_unlock; |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 7de2814d527e..7caa26eb4105 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -178,12 +178,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate) | |||
178 | } | 178 | } |
179 | 179 | ||
180 | /* Generate a TX data header. */ | 180 | /* Generate a TX data header. */ |
181 | void b43_generate_txhdr(struct b43_wldev *dev, | 181 | int b43_generate_txhdr(struct b43_wldev *dev, |
182 | u8 *_txhdr, | 182 | u8 *_txhdr, |
183 | const unsigned char *fragment_data, | 183 | const unsigned char *fragment_data, |
184 | unsigned int fragment_len, | 184 | unsigned int fragment_len, |
185 | const struct ieee80211_tx_control *txctl, | 185 | const struct ieee80211_tx_control *txctl, |
186 | u16 cookie) | 186 | u16 cookie) |
187 | { | 187 | { |
188 | struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; | 188 | struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; |
189 | const struct b43_phy *phy = &dev->phy; | 189 | const struct b43_phy *phy = &dev->phy; |
@@ -238,22 +238,27 @@ void b43_generate_txhdr(struct b43_wldev *dev, | |||
238 | B43_WARN_ON(key_idx >= dev->max_nr_keys); | 238 | B43_WARN_ON(key_idx >= dev->max_nr_keys); |
239 | key = &(dev->key[key_idx]); | 239 | key = &(dev->key[key_idx]); |
240 | 240 | ||
241 | if (likely(key->keyconf)) { | 241 | if (unlikely(!key->keyconf)) { |
242 | /* This key is valid. Use it for encryption. */ | 242 | /* This key is invalid. This might only happen |
243 | 243 | * in a short timeframe after machine resume before | |
244 | /* Hardware appends ICV. */ | 244 | * we were able to reconfigure keys. |
245 | plcp_fragment_len += txctl->icv_len; | 245 | * Drop this packet completely. Do not transmit it |
246 | 246 | * unencrypted to avoid leaking information. */ | |
247 | key_idx = b43_kidx_to_fw(dev, key_idx); | 247 | return -ENOKEY; |
248 | mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & | ||
249 | B43_TXH_MAC_KEYIDX; | ||
250 | mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & | ||
251 | B43_TXH_MAC_KEYALG; | ||
252 | wlhdr_len = ieee80211_get_hdrlen(fctl); | ||
253 | iv_len = min((size_t) txctl->iv_len, | ||
254 | ARRAY_SIZE(txhdr->iv)); | ||
255 | memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); | ||
256 | } | 248 | } |
249 | |||
250 | /* Hardware appends ICV. */ | ||
251 | plcp_fragment_len += txctl->icv_len; | ||
252 | |||
253 | key_idx = b43_kidx_to_fw(dev, key_idx); | ||
254 | mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & | ||
255 | B43_TXH_MAC_KEYIDX; | ||
256 | mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & | ||
257 | B43_TXH_MAC_KEYALG; | ||
258 | wlhdr_len = ieee80211_get_hdrlen(fctl); | ||
259 | iv_len = min((size_t) txctl->iv_len, | ||
260 | ARRAY_SIZE(txhdr->iv)); | ||
261 | memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); | ||
257 | } | 262 | } |
258 | if (b43_is_old_txhdr_format(dev)) { | 263 | if (b43_is_old_txhdr_format(dev)) { |
259 | b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), | 264 | b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), |
@@ -411,6 +416,7 @@ void b43_generate_txhdr(struct b43_wldev *dev, | |||
411 | txhdr->phy_ctl = cpu_to_le16(phy_ctl); | 416 | txhdr->phy_ctl = cpu_to_le16(phy_ctl); |
412 | txhdr->extra_ft = extra_ft; | 417 | txhdr->extra_ft = extra_ft; |
413 | 418 | ||
419 | return 0; | ||
414 | } | 420 | } |
415 | 421 | ||
416 | static s8 b43_rssi_postprocess(struct b43_wldev *dev, | 422 | static s8 b43_rssi_postprocess(struct b43_wldev *dev, |
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index ca2a2ab8654c..41765039552b 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h | |||
@@ -174,11 +174,11 @@ size_t b43_txhdr_size(struct b43_wldev *dev) | |||
174 | } | 174 | } |
175 | 175 | ||
176 | 176 | ||
177 | void b43_generate_txhdr(struct b43_wldev *dev, | 177 | int b43_generate_txhdr(struct b43_wldev *dev, |
178 | u8 * txhdr, | 178 | u8 * txhdr, |
179 | const unsigned char *fragment_data, | 179 | const unsigned char *fragment_data, |
180 | unsigned int fragment_len, | 180 | unsigned int fragment_len, |
181 | const struct ieee80211_tx_control *txctl, u16 cookie); | 181 | const struct ieee80211_tx_control *txctl, u16 cookie); |
182 | 182 | ||
183 | /* Transmit Status */ | 183 | /* Transmit Status */ |
184 | struct b43_txstatus { | 184 | struct b43_txstatus { |