Search Linux Wireless

[PATCH] b43: Drop packets that we are not able to encrypt

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>

---

This is _not_ only a theoretical problem. I saw a few packets hitting
this race condition.

John, please try to push for 2.6.24, as this is a security fix.

Stefano, this might need porting to legacy.


Index: wireless-2.6/drivers/net/wireless/b43/dma.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/dma.c	2008-01-22 18:43:47.000000000 +0100
+++ wireless-2.6/drivers/net/wireless/b43/dma.c	2008-01-23 21:34:42.000000000 +0100
@@ -1111,38 +1111,49 @@ struct b43_dmaring *parse_cookie(struct 
 static int dma_tx_fragment(struct b43_dmaring *ring,
 			   struct sk_buff *skb,
 			   struct ieee80211_tx_control *ctl)
 {
 	const struct b43_dma_ops *ops = ring->ops;
 	u8 *header;
-	int slot;
+	int slot, old_top_slot, old_used_slots;
 	int err;
 	struct b43_dmadesc_generic *desc;
 	struct b43_dmadesc_meta *meta;
 	struct b43_dmadesc_meta *meta_hdr;
 	struct sk_buff *bounce_skb;
 	u16 cookie;
 	size_t hdrsize = b43_txhdr_size(ring->dev);
 
 #define SLOTS_PER_PACKET  2
 	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 
+	old_top_slot = ring->current_slot;
+	old_used_slots = ring->used_slots;
+
 	/* Get a slot for the header. */
 	slot = request_slot(ring);
 	desc = ops->idx2desc(ring, slot, &meta_hdr);
 	memset(meta_hdr, 0, sizeof(*meta_hdr));
 
 	header = &(ring->txhdr_cache[slot * hdrsize]);
 	cookie = generate_cookie(ring, slot);
-	b43_generate_txhdr(ring->dev, header,
-			   skb->data, skb->len, ctl, cookie);
+	err = b43_generate_txhdr(ring->dev, header,
+				 skb->data, skb->len, ctl, cookie);
+	if (unlikely(err)) {
+		ring->current_slot = old_top_slot;
+		ring->used_slots = old_used_slots;
+		return err;
+	}
 
 	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
 					   hdrsize, 1);
-	if (dma_mapping_error(meta_hdr->dmaaddr))
+	if (dma_mapping_error(meta_hdr->dmaaddr)) {
+		ring->current_slot = old_top_slot;
+		ring->used_slots = old_used_slots;
 		return -EIO;
+	}
 	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
 			     hdrsize, 1, 0, 0);
 
 	/* Get a slot for the payload. */
 	slot = request_slot(ring);
 	desc = ops->idx2desc(ring, slot, &meta);
@@ -1154,22 +1165,26 @@ static int dma_tx_fragment(struct b43_dm
 
 	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	/* create a bounce buffer in zone_dma on mapping failure. */
 	if (dma_mapping_error(meta->dmaaddr)) {
 		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb) {
+			ring->current_slot = old_top_slot;
+			ring->used_slots = old_used_slots;
 			err = -ENOMEM;
 			goto out_unmap_hdr;
 		}
 
 		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
 		dev_kfree_skb_any(skb);
 		skb = bounce_skb;
 		meta->skb = skb;
 		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 		if (dma_mapping_error(meta->dmaaddr)) {
+			ring->current_slot = old_top_slot;
+			ring->used_slots = old_used_slots;
 			err = -EIO;
 			goto out_free_bounce;
 		}
 	}
 
 	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
@@ -1249,12 +1264,19 @@ int b43_dma_tx(struct b43_wldev *dev,
 	/* Check if the queue was stopped in mac80211,
 	 * but we got called nevertheless.
 	 * That would be a mac80211 bug. */
 	B43_WARN_ON(ring->stopped);
 
 	err = dma_tx_fragment(ring, skb, ctl);
+	if (unlikely(err == -ENOKEY)) {
+		/* Drop this packet, as we don't have the encryption key
+		 * anymore and must not transmit it unencrypted. */
+		dev_kfree_skb_any(skb);
+		err = 0;
+		goto out_unlock;
+	}
 	if (unlikely(err)) {
 		b43err(dev->wl, "DMA tx mapping failure\n");
 		goto out_unlock;
 	}
 	ring->nr_tx_packets++;
 	if ((free_slots(ring) < SLOTS_PER_PACKET) ||
Index: wireless-2.6/drivers/net/wireless/b43/xmit.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/xmit.c	2008-01-23 21:02:16.000000000 +0100
+++ wireless-2.6/drivers/net/wireless/b43/xmit.c	2008-01-23 21:34:53.000000000 +0100
@@ -175,18 +175,18 @@ static u8 b43_calc_fallback_rate(u8 bitr
 	}
 	B43_WARN_ON(1);
 	return 0;
 }
 
 /* Generate a TX data header. */
-void b43_generate_txhdr(struct b43_wldev *dev,
-			u8 *_txhdr,
-			const unsigned char *fragment_data,
-			unsigned int fragment_len,
-			const struct ieee80211_tx_control *txctl,
-			u16 cookie)
+int b43_generate_txhdr(struct b43_wldev *dev,
+		       u8 *_txhdr,
+		       const unsigned char *fragment_data,
+		       unsigned int fragment_len,
+		       const struct ieee80211_tx_control *txctl,
+		       u16 cookie)
 {
 	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
 	const struct b43_phy *phy = &dev->phy;
 	const struct ieee80211_hdr *wlhdr =
 	    (const struct ieee80211_hdr *)fragment_data;
 	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
@@ -235,28 +235,33 @@ void b43_generate_txhdr(struct b43_wldev
 		int wlhdr_len;
 		size_t iv_len;
 
 		B43_WARN_ON(key_idx >= dev->max_nr_keys);
 		key = &(dev->key[key_idx]);
 
-		if (likely(key->keyconf)) {
-			/* This key is valid. Use it for encryption. */
+		if (unlikely(!key->keyconf)) {
+			/* This key is invalid. This might only happen
+			 * in a short timeframe after machine resume before
+			 * we were able to reconfigure keys.
+			 * Drop this packet completely. Do not transmit it
+			 * unencrypted to avoid leaking information. */
+			return -ENOKEY;
+		}
 
-			/* Hardware appends ICV. */
-			plcp_fragment_len += txctl->icv_len;
+		/* Hardware appends ICV. */
+		plcp_fragment_len += txctl->icv_len;
 
-			key_idx = b43_kidx_to_fw(dev, key_idx);
-			mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
-				   B43_TXH_MAC_KEYIDX;
-			mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
-				   B43_TXH_MAC_KEYALG;
-			wlhdr_len = ieee80211_get_hdrlen(fctl);
-			iv_len = min((size_t) txctl->iv_len,
-				     ARRAY_SIZE(txhdr->iv));
-			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
-		}
+		key_idx = b43_kidx_to_fw(dev, key_idx);
+		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
+			   B43_TXH_MAC_KEYIDX;
+		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
+			   B43_TXH_MAC_KEYALG;
+		wlhdr_len = ieee80211_get_hdrlen(fctl);
+		iv_len = min((size_t) txctl->iv_len,
+			     ARRAY_SIZE(txhdr->iv));
+		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 	}
 	if (b43_is_old_txhdr_format(dev)) {
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
 				      plcp_fragment_len, rate);
 	} else {
 		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
@@ -408,12 +413,13 @@ void b43_generate_txhdr(struct b43_wldev
 
 	/* Apply the bitfields */
 	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
 	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
 	txhdr->extra_ft = extra_ft;
 
+	return 0;
 }
 
 static s8 b43_rssi_postprocess(struct b43_wldev *dev,
 			       u8 in_rssi, int ofdm,
 			       int adjust_2053, int adjust_2050)
 {
Index: wireless-2.6/drivers/net/wireless/b43/xmit.h
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/xmit.h	2008-01-23 12:38:42.000000000 +0100
+++ wireless-2.6/drivers/net/wireless/b43/xmit.h	2008-01-23 21:13:02.000000000 +0100
@@ -171,17 +171,17 @@ size_t b43_txhdr_size(struct b43_wldev *
 	if (b43_is_old_txhdr_format(dev))
 		return 100 + sizeof(struct b43_plcp_hdr6);
 	return 104 + sizeof(struct b43_plcp_hdr6);
 }
 
 
-void b43_generate_txhdr(struct b43_wldev *dev,
-			u8 * txhdr,
-			const unsigned char *fragment_data,
-			unsigned int fragment_len,
-			const struct ieee80211_tx_control *txctl, u16 cookie);
+int b43_generate_txhdr(struct b43_wldev *dev,
+		       u8 * txhdr,
+		       const unsigned char *fragment_data,
+		       unsigned int fragment_len,
+		       const struct ieee80211_tx_control *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
 	u16 cookie;		/* The cookie from the txhdr */
 	u16 seq;		/* Sequence number */
 	u8 phy_stat;		/* PHY TX status */
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux