Forráskód Böngészése

mac80211: validate DA/SA during A-MSDU decapsulation

As pointed out by Michael Braun, we don't check inner L2 addresses
during A-MSDU decapsulation, leading to the possibility that, for
example, a station associated to an AP sends frames as though they
came from somewhere else.

Fix this problem by letting cfg80211 validate the addresses, as
indicated by passing in the ones that need to be validated.

Reported-by: Michael Braun <michael-dev@fami-braun.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Johannes Berg 8 éve
szülő
commit
e2b5227faa
1 módosított fájl, 19 hozzáadás és 1 törlés
  1. 19 1
      net/mac80211/rx.c

+ 19 - 1
net/mac80211/rx.c

@@ -2299,6 +2299,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 	struct sk_buff_head frame_list;
 	struct sk_buff_head frame_list;
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 	struct ethhdr ethhdr;
 	struct ethhdr ethhdr;
+	const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
 
 
 	if (unlikely(!ieee80211_is_data(fc)))
 	if (unlikely(!ieee80211_is_data(fc)))
 		return RX_CONTINUE;
 		return RX_CONTINUE;
@@ -2322,6 +2323,23 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 		default:
 		default:
 			return RX_DROP_UNUSABLE;
 			return RX_DROP_UNUSABLE;
 		}
 		}
+		check_da = NULL;
+		check_sa = NULL;
+	} else switch (rx->sdata->vif.type) {
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_AP_VLAN:
+			check_da = NULL;
+			break;
+		case NL80211_IFTYPE_STATION:
+			if (!rx->sta ||
+			    !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+				check_sa = NULL;
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			check_sa = NULL;
+			break;
+		default:
+			break;
 	}
 	}
 
 
 	if (is_multicast_ether_addr(hdr->addr1))
 	if (is_multicast_ether_addr(hdr->addr1))
@@ -2338,7 +2356,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 	ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
 	ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
 				 rx->sdata->vif.type,
 				 rx->sdata->vif.type,
 				 rx->local->hw.extra_tx_headroom,
 				 rx->local->hw.extra_tx_headroom,
-				 NULL, NULL);
+				 check_da, check_sa);
 
 
 	while (!skb_queue_empty(&frame_list)) {
 	while (!skb_queue_empty(&frame_list)) {
 		rx->skb = __skb_dequeue(&frame_list);
 		rx->skb = __skb_dequeue(&frame_list);