lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1385039154-20637-1-git-send-email-johannes@sipsolutions.net>
Date:	Thu, 21 Nov 2013 14:05:54 +0100
From:	Johannes Berg <johannes@...solutions.net>
To:	linux-wireless@...r.kernel.org, netdev@...r.kernel.org
Cc:	Jouni Malinen <jouni@....qualcomm.com>
Subject: [RFC] wireless, ipv4, ipv6: drop GTK-protected unicast IP packets

From: Jouni Malinen <jouni@....qualcomm.com>

The GTK is shared by all stations in an 802.11 BSS and as such any
one of them can send forged group-addressed frames. To prevent this
kind of attack, drop unicast IP packets if they were protected with
the GTK, i.e. were multicast packets at the 802.11 layer.

Signed-off-by: Jouni Malinen <jouni@....qualcomm.com>
[configuration, IPv6]
Signed-off-by: Johannes Berg <johannes.berg@...el.com>
---
 include/linux/skbuff.h       |  5 ++++-
 include/net/cfg80211.h       |  7 +++++--
 include/uapi/linux/nl80211.h |  6 ++++++
 net/core/skbuff.c            |  1 +
 net/ipv4/ip_input.c          | 12 ++++++++++++
 net/ipv6/ip6_input.c         | 11 +++++++++++
 net/mac80211/ieee80211_i.h   |  3 ++-
 net/mac80211/mlme.c          |  2 ++
 net/mac80211/rx.c            |  7 +++++++
 net/wireless/nl80211.c       |  4 ++++
 10 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2ddb48d..5ed5a19 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -384,6 +384,8 @@ typedef unsigned char *sk_buff_data_t;
  *	@wifi_acked_valid: wifi_acked was set
  *	@wifi_acked: whether frame was acked on wifi or not
  *	@no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS
+ *	@drop_unicast: Request protocols to drop frame if it's a unicast frame
+ *		in that protocol - used for frames received over wifi multicast
  *	@dma_cookie: a cookie to one of several possible DMA operations
  *		done by skb DMA functions
   *	@napi_id: id of the NAPI struct this skb came from
@@ -498,7 +500,8 @@ struct sk_buff {
 	 * headers if needed
 	 */
 	__u8			encapsulation:1;
-	/* 7/9 bit hole (depending on ndisc_nodetype presence) */
+	__u8			drop_unicast:1;
+	/* 6/8 bit hole (depending on ndisc_nodetype presence) */
 	kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6c2bc329..37a4c09 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1560,10 +1560,13 @@ struct cfg80211_auth_request {
  *
  * @ASSOC_REQ_DISABLE_HT:  Disable HT (802.11n)
  * @ASSOC_REQ_DISABLE_VHT:  Disable VHT
+ * @ASSOC_REQ_DROP_GROUP_PROTECTED_UNICAST: Drop protocol unicast packets
+ *	that were group-protected at the link layer.
  */
 enum cfg80211_assoc_req_flags {
-	ASSOC_REQ_DISABLE_HT		= BIT(0),
-	ASSOC_REQ_DISABLE_VHT		= BIT(1),
+	ASSOC_REQ_DISABLE_HT			= BIT(0),
+	ASSOC_REQ_DISABLE_VHT			= BIT(1),
+	ASSOC_REQ_DROP_GROUP_PROTECTED_UNICAST	= BIT(2),
 };
 
 /**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 4bb8289..8fc8b05 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1518,6 +1518,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_SUPPORT_5_10_MHZ: A flag indicating that the device supports
  *	5 MHz and 10 MHz channel bandwidth.
  *
+ * @NL80211_ATTR_DROP_GROUP_PROTECTED_UNICAST: Drop protocol unicast packets
+ *	that were group protected at the wireless level. This flag attribute
+ *	is valid in the association command.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1836,6 +1840,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_SUPPORT_5_10_MHZ,
 
+	NL80211_ATTR_DROP_GROUP_PROTECTED_UNICAST,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d81cff1..b751e7d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -737,6 +737,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 #endif
 	new->vlan_proto		= old->vlan_proto;
 	new->vlan_tci		= old->vlan_tci;
+	new->drop_unicast	= old->drop_unicast;
 
 	skb_copy_secmark(new, old);
 
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 054a3e9..7de7f84 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -363,6 +363,18 @@ static int ip_rcv_finish(struct sk_buff *skb)
 		IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INBCAST,
 				skb->len);
 
+	/*
+	 * If the received packet was protected in a way that would allow
+	 * insider attacks (e.g. IEEE 802.11 networks with GTK shared for all
+	 * associated stations in an BSS), group-addressed link layer frames
+	 * can be forged. To reduce the effects of such an attack, drop the
+	 * packet if it is destined to unicast address, but was sent in a
+	 * group-addressed link layer frame.
+	 */
+	if (unlikely(skb->drop_unicast &&
+		     (rt->rt_type == RTN_UNICAST || rt->rt_type == RTN_LOCAL)))
+		goto drop;
+
 	return dst_input(skb);
 
 drop:
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 302d6fb..d9cbf4d 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -151,6 +151,17 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 	if (ipv6_addr_is_multicast(&hdr->saddr))
 		goto err;
 
+	/*
+	 * If the received packet was protected in a way that would allow
+	 * insider attacks (e.g. IEEE 802.11 networks with GTK shared for all
+	 * associated stations in an BSS), group-addressed link layer frames
+	 * can be forged. To reduce the effects of such an attack, drop the
+	 * packet if it is destined to unicast address, but was sent in a
+	 * group-addressed link layer frame.
+	 */
+	if (unlikely(skb->drop_unicast && !ipv6_addr_is_multicast(&hdr->daddr)))
+		goto err;
+
 	skb->transport_header = skb->network_header + sizeof(*hdr);
 	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 61ccf0d..d39cfb5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -705,7 +705,8 @@ struct ieee80211_sub_if_data {
 
 	unsigned long state;
 
-	int drop_unencrypted;
+	bool drop_unencrypted;
+	bool drop_group_protected_unicast;
 
 	char name[IFNAMSIZ];
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e7f0d53..649902b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4121,6 +4121,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
 	sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
 							sdata->vif.type);
+	sdata->drop_group_protected_unicast =
+		req->flags & ASSOC_REQ_DROP_GROUP_PROTECTED_UNICAST;
 
 	/* kick off associate process */
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5638782..2095be1 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1544,6 +1544,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 			    !is_multicast_ether_addr(hdr->addr1))
 				rx->key = NULL;
 		}
+
+		if (rx->key && is_multicast_ether_addr(hdr->addr1) &&
+		    rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+		    rx->sdata->drop_group_protected_unicast &&
+		    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+		    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104)
+			rx->skb->drop_unicast = 1;
 	}
 
 	if (rx->key) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e39fadc..f8e3c83 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -357,6 +357,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 	[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
 	[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
 	[NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
+	[NL80211_ATTR_DROP_GROUP_PROTECTED_UNICAST] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -6345,6 +6346,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 		       sizeof(req.vht_capa));
 	}
 
+	if (info->attrs[NL80211_ATTR_DROP_GROUP_PROTECTED_UNICAST])
+		req.flags |= ASSOC_REQ_DROP_GROUP_PROTECTED_UNICAST;
+
 	err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
 	if (!err) {
 		wdev_lock(dev->ieee80211_ptr);
-- 
1.8.4.rc3

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ