Commit 8b935ee2 authored by Johannes Berg's avatar Johannes Berg

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: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7f6990c8
...@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, ...@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev.iftype, 0); priv->wdev.iftype, 0, NULL, NULL);
while (!skb_queue_empty(&list)) { while (!skb_queue_empty(&list)) {
struct rx_packet_hdr *rx_hdr; struct rx_packet_hdr *rx_hdr;
......
...@@ -4090,10 +4090,13 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, ...@@ -4090,10 +4090,13 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
* @addr: The device MAC address. * @addr: The device MAC address.
* @iftype: The device interface type. * @iftype: The device interface type.
* @extra_headroom: The hardware extra headroom for SKBs in the @list. * @extra_headroom: The hardware extra headroom for SKBs in the @list.
* @check_da: DA to check in the inner ethernet header, or NULL
* @check_sa: SA to check in the inner ethernet header, or NULL
*/ */
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype, const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom); const unsigned int extra_headroom,
const u8 *check_da, const u8 *check_sa);
/** /**
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
......
...@@ -2337,7 +2337,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ...@@ -2337,7 +2337,8 @@ 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);
while (!skb_queue_empty(&frame_list)) { while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&frame_list); rx->skb = __skb_dequeue(&frame_list);
......
...@@ -739,7 +739,8 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, ...@@ -739,7 +739,8 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype, const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom) const unsigned int extra_headroom,
const u8 *check_da, const u8 *check_sa)
{ {
unsigned int hlen = ALIGN(extra_headroom, 4); unsigned int hlen = ALIGN(extra_headroom, 4);
struct sk_buff *frame = NULL; struct sk_buff *frame = NULL;
...@@ -767,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, ...@@ -767,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
goto purge; goto purge;
offset += sizeof(struct ethhdr); offset += sizeof(struct ethhdr);
/* reuse skb for the last subframe */
last = remaining <= subframe_len + padding; last = remaining <= subframe_len + padding;
/* FIXME: should we really accept multicast DA? */
if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
!ether_addr_equal(check_da, eth.h_dest)) ||
(check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
offset += len + padding;
continue;
}
/* reuse skb for the last subframe */
if (!skb_is_nonlinear(skb) && !reuse_frag && last) { if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
skb_pull(skb, offset); skb_pull(skb, offset);
frame = skb; frame = skb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment