[linux] 01/03: net: add recursion limit to GRO (CVE-2016-7039)

debian-kernel at lists.debian.org debian-kernel at lists.debian.org
Wed Oct 12 23:28:13 UTC 2016


This is an automated email from the git hooks/post-receive script.

benh pushed a commit to branch sid
in repository linux.

commit c27b72f255bfc1f41ec6216e5db605cb6223e5cf
Author: Ben Hutchings <ben at decadent.org.uk>
Date:   Thu Oct 13 00:17:03 2016 +0100

    net: add recursion limit to GRO (CVE-2016-7039)
---
 debian/changelog                                   |   3 +
 .../all/net-add-recursion-limit-to-gro.patch       | 201 +++++++++++++++++++++
 .../gro-fix-abi-change-for-cve-2016-7039-fix.patch |  33 ++++
 debian/patches/series                              |   2 +
 4 files changed, 239 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 6859851..81d4c64 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -124,6 +124,9 @@ linux (4.7.7-1) UNRELEASED; urgency=medium
       laptops
     - [x86] ALSA: hda - Add the top speaker pin config for HP Spectre x360
 
+  [ Ben Hutchings ]
+  * net: add recursion limit to GRO (CVE-2016-7039)
+
  -- Ben Hutchings <ben at decadent.org.uk>  Tue, 11 Oct 2016 22:43:14 +0100
 
 linux (4.7.6-1) unstable; urgency=medium
diff --git a/debian/patches/bugfix/all/net-add-recursion-limit-to-gro.patch b/debian/patches/bugfix/all/net-add-recursion-limit-to-gro.patch
new file mode 100644
index 0000000..d6cfd4b
--- /dev/null
+++ b/debian/patches/bugfix/all/net-add-recursion-limit-to-gro.patch
@@ -0,0 +1,201 @@
+From: Sabrina Dubroca <sd at queasysnail.net>
+Date: Mon, 10 Oct 2016 15:43:46 +0200
+Subject: net: add recursion limit to GRO
+Origin: https://patchwork.ozlabs.org/patch/680412/
+
+Currently, GRO can do unlimited recursion through the gro_receive
+handlers.  This was fixed for tunneling protocols by limiting tunnel GRO
+to one level with encap_mark, but both VLAN and TEB still have this
+problem.  Thus, the kernel is vulnerable to a stack overflow, if we
+receive a packet composed entirely of VLAN headers.
+
+This patch adds a recursion counter to the GRO layer to prevent stack
+overflow.  When a gro_receive function hits the recursion limit, GRO is
+aborted for this skb and it is processed normally.
+
+Thanks to Vladimír Beneš <vbenes at redhat.com> for the initial bug report.
+
+Fixes: CVE-2016-7039
+Fixes: 9b174d88c257 ("net: Add Transparent Ethernet Bridging GRO support.")
+Fixes: 66e5133f19e9 ("vlan: Add GRO support for non hardware accelerated vlan")
+Signed-off-by: Sabrina Dubroca <sd at queasysnail.net>
+Reviewed-by: Jiri Benc <jbenc at redhat.com>
+Acked-by: Hannes Frederic Sowa <hannes at stressinduktion.org>
+---
+ drivers/net/geneve.c      |  2 +-
+ drivers/net/vxlan.c       |  2 +-
+ include/linux/netdevice.h | 24 +++++++++++++++++++++++-
+ net/8021q/vlan.c          |  2 +-
+ net/core/dev.c            |  1 +
+ net/ethernet/eth.c        |  2 +-
+ net/ipv4/af_inet.c        |  2 +-
+ net/ipv4/fou.c            |  4 ++--
+ net/ipv4/gre_offload.c    |  2 +-
+ net/ipv4/udp_offload.c    |  8 +++++++-
+ net/ipv6/ip6_offload.c    |  2 +-
+ 11 files changed, 40 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -471,7 +471,7 @@ static struct sk_buff **geneve_gro_recei
+ 
+ 	skb_gro_pull(skb, gh_len);
+ 	skb_gro_postpull_rcsum(skb, gh, gh_len);
+-	pp = ptype->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 	flush = 0;
+ 
+ out_unlock:
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -601,7 +601,7 @@ static struct sk_buff **vxlan_gro_receiv
+ 		}
+ 	}
+ 
+-	pp = eth_gro_receive(head, skb);
++	pp = call_gro_receive(eth_gro_receive, head, skb);
+ 	flush = 0;
+ 
+ out:
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -2114,7 +2114,10 @@ struct napi_gro_cb {
+ 	/* Used to determine if flush_id can be ignored */
+ 	u8	is_atomic:1;
+ 
+-	/* 5 bit hole */
++	/* Number of gro_receive callbacks this packet already went through */
++	u8 recursion_counter:4;
++
++	/* 1 bit hole */
+ 
+ 	/* used to support CHECKSUM_COMPLETE for tunneling protocols */
+ 	__wsum	csum;
+@@ -2125,6 +2128,25 @@ struct napi_gro_cb {
+ 
+ #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+ 
++#define GRO_RECURSION_LIMIT 15
++static inline int gro_recursion_inc_test(struct sk_buff *skb)
++{
++	return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
++}
++
++typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *);
++static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
++						struct sk_buff **head,
++						struct sk_buff *skb)
++{
++	if (gro_recursion_inc_test(skb)) {
++		NAPI_GRO_CB(skb)->flush |= 1;
++		return NULL;
++	}
++
++	return cb(head, skb);
++}
++
+ struct packet_type {
+ 	__be16			type;	/* This is really htons(ether_type). */
+ 	struct net_device	*dev;	/* NULL is wildcarded here	     */
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive
+ 
+ 	skb_gro_pull(skb, sizeof(*vhdr));
+ 	skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
+-	pp = ptype->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4500,6 +4500,7 @@ static enum gro_result dev_gro_receive(s
+ 		NAPI_GRO_CB(skb)->flush = 0;
+ 		NAPI_GRO_CB(skb)->free = 0;
+ 		NAPI_GRO_CB(skb)->encap_mark = 0;
++		NAPI_GRO_CB(skb)->recursion_counter = 0;
+ 		NAPI_GRO_CB(skb)->is_fou = 0;
+ 		NAPI_GRO_CB(skb)->is_atomic = 1;
+ 		NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -439,7 +439,7 @@ struct sk_buff **eth_gro_receive(struct
+ 
+ 	skb_gro_pull(skb, sizeof(*eh));
+ 	skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
+-	pp = ptype->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1388,7 +1388,7 @@ struct sk_buff **inet_gro_receive(struct
+ 	skb_gro_pull(skb, sizeof(*iph));
+ 	skb_set_transport_header(skb, skb_gro_offset(skb));
+ 
+-	pp = ops->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+--- a/net/ipv4/fou.c
++++ b/net/ipv4/fou.c
+@@ -219,7 +219,7 @@ static struct sk_buff **fou_gro_receive(
+ 	if (!ops || !ops->callbacks.gro_receive)
+ 		goto out_unlock;
+ 
+-	pp = ops->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+@@ -387,7 +387,7 @@ static struct sk_buff **gue_gro_receive(
+ 	if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
+ 		goto out_unlock;
+ 
+-	pp = ops->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 	flush = 0;
+ 
+ out_unlock:
+--- a/net/ipv4/gre_offload.c
++++ b/net/ipv4/gre_offload.c
+@@ -227,7 +227,7 @@ static struct sk_buff **gre_gro_receive(
+ 	/* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
+ 	skb_gro_postpull_rcsum(skb, greh, grehlen);
+ 
+-	pp = ptype->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 	flush = 0;
+ 
+ out_unlock:
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -293,7 +293,13 @@ unflush:
+ 
+ 	skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
+ 	skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
+-	pp = udp_sk(sk)->gro_receive(sk, head, skb);
++
++	if (gro_recursion_inc_test(skb)) {
++		flush = 1;
++		pp = NULL;
++	} else {
++		pp = udp_sk(sk)->gro_receive(sk, head, skb);
++	}
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -243,7 +243,7 @@ static struct sk_buff **ipv6_gro_receive
+ 
+ 	skb_gro_postpull_rcsum(skb, iph, nlen);
+ 
+-	pp = ops->callbacks.gro_receive(head, skb);
++	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
diff --git a/debian/patches/debian/gro-fix-abi-change-for-cve-2016-7039-fix.patch b/debian/patches/debian/gro-fix-abi-change-for-cve-2016-7039-fix.patch
new file mode 100644
index 0000000..356010b
--- /dev/null
+++ b/debian/patches/debian/gro-fix-abi-change-for-cve-2016-7039-fix.patch
@@ -0,0 +1,33 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Thu, 13 Oct 2016 00:05:23 +0100
+Subject: gro: Fix ABI change for CVE-2016-7039 fix
+Forwarded: not-needed
+
+The fix for CVE-2016-7039 (unbounded recursion in GRO) added a 4-bit
+bitfield in struct napi_gro_cb where there used to be padding, so
+the structure layout hasn't changed.
+
+In case of a version mismatch between kernel and modules, two things
+could go wrong, but they are not disastrous:
+
+- the recursion count is not incremented and checked when it should
+  be, so the fix is incomplete - no worse than before
+- the recursion count is not reset, so GRO is not effective - only
+  a performance problem
+
+So hide this change from genksyms.
+
+---
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -2114,8 +2114,10 @@ struct napi_gro_cb {
+ 	/* Used to determine if flush_id can be ignored */
+ 	u8	is_atomic:1;
+ 
++#ifndef __GENKSYMS__
+ 	/* Number of gro_receive callbacks this packet already went through */
+ 	u8 recursion_counter:4;
++#endif
+ 
+ 	/* 1 bit hole */
+ 
diff --git a/debian/patches/series b/debian/patches/series
index dd0e47e..950f06e 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -114,12 +114,14 @@ features/all/securelevel/arm64-add-kernel-config-option-to-set-securelevel-wh.pa
 # Security fixes
 bugfix/all/ptrace-being-capable-wrt-a-process-requires-mapped-uids-gids.patch
 debian/i386-686-pae-pci-set-pci-nobios-by-default.patch
+bugfix/all/net-add-recursion-limit-to-gro.patch
 
 # ABI maintenance
 debian/i8042-revert-abi-break-in-4.7.3.patch
 debian/revert-arm64-define-at_vector_size_arch-for-arch_dlinfo.patch
 debian/uaccess-avoid-abi-change-in-4.7.5.patch
 debian/uio-fix-abi-change-in-4.7.5.patch
+debian/gro-fix-abi-change-for-cve-2016-7039-fix.patch
 
 # Tools bug fixes
 bugfix/all/usbip-document-tcp-wrappers.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git



More information about the Kernel-svn-changes mailing list