Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: add ability to check DA/SA in A-MSDU decapsulation

We should not accept arbitrary DA/SA inside A-MSDUs, it could be used
to circumvent protections, like allowing a station to send frames and
make them seem to come from somewhere else.

Add the necessary infrastructure in cfg80211 to allow such checks, in
further patches we'll start using them.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>

+19 -5
+1 -1
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
··· 45 45 skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); 46 46 47 47 ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, 48 - priv->wdev.iftype, 0); 48 + priv->wdev.iftype, 0, NULL, NULL); 49 49 50 50 while (!skb_queue_empty(&list)) { 51 51 struct rx_packet_hdr *rx_hdr;
+4 -1
include/net/cfg80211.h
··· 4090 4090 * @addr: The device MAC address. 4091 4091 * @iftype: The device interface type. 4092 4092 * @extra_headroom: The hardware extra headroom for SKBs in the @list. 4093 + * @check_da: DA to check in the inner ethernet header, or NULL 4094 + * @check_sa: SA to check in the inner ethernet header, or NULL 4093 4095 */ 4094 4096 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, 4095 4097 const u8 *addr, enum nl80211_iftype iftype, 4096 - const unsigned int extra_headroom); 4098 + const unsigned int extra_headroom, 4099 + const u8 *check_da, const u8 *check_sa); 4097 4100 4098 4101 /** 4099 4102 * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
+2 -1
net/mac80211/rx.c
··· 2337 2337 2338 2338 ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, 2339 2339 rx->sdata->vif.type, 2340 - rx->local->hw.extra_tx_headroom); 2340 + rx->local->hw.extra_tx_headroom, 2341 + NULL, NULL); 2341 2342 2342 2343 while (!skb_queue_empty(&frame_list)) { 2343 2344 rx->skb = __skb_dequeue(&frame_list);
+12 -2
net/wireless/util.c
··· 739 739 740 740 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, 741 741 const u8 *addr, enum nl80211_iftype iftype, 742 - const unsigned int extra_headroom) 742 + const unsigned int extra_headroom, 743 + const u8 *check_da, const u8 *check_sa) 743 744 { 744 745 unsigned int hlen = ALIGN(extra_headroom, 4); 745 746 struct sk_buff *frame = NULL; ··· 768 767 goto purge; 769 768 770 769 offset += sizeof(struct ethhdr); 771 - /* reuse skb for the last subframe */ 772 770 last = remaining <= subframe_len + padding; 771 + 772 + /* FIXME: should we really accept multicast DA? */ 773 + if ((check_da && !is_multicast_ether_addr(eth.h_dest) && 774 + !ether_addr_equal(check_da, eth.h_dest)) || 775 + (check_sa && !ether_addr_equal(check_sa, eth.h_source))) { 776 + offset += len + padding; 777 + continue; 778 + } 779 + 780 + /* reuse skb for the last subframe */ 773 781 if (!skb_is_nonlinear(skb) && !reuse_frag && last) { 774 782 skb_pull(skb, offset); 775 783 frame = skb;