From 0368c4076f4017571a5e8a617763859a84277427 Mon Sep 17 00:00:00 2001 From: Andreas Wellving Date: Wed, 17 Oct 2018 14:06:25 +0200 Subject: net: CVE-2016-7039 net: add recursion limit to GRO References: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.1.y&id=fabaaaa96d54077b4a9f2c811e55dc09ff2874db Change-Id: Ice78062187e95abdffb700d3f247e98173886a22 Signed-off-by: Andreas Wellving --- patches/cve/4.1.x.scc | 2 + ...-2016-7039-net-add-recursion-limit-to-GRO.patch | 209 +++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 patches/cve/4.1.x.scc create mode 100644 patches/cve/CVE-2016-7039-net-add-recursion-limit-to-GRO.patch diff --git a/patches/cve/4.1.x.scc b/patches/cve/4.1.x.scc new file mode 100644 index 0000000..613c8d9 --- /dev/null +++ b/patches/cve/4.1.x.scc @@ -0,0 +1,2 @@ +#fixed in 4.1.37 +patch CVE-2016-7039-net-add-recursion-limit-to-GRO.patch diff --git a/patches/cve/CVE-2016-7039-net-add-recursion-limit-to-GRO.patch b/patches/cve/CVE-2016-7039-net-add-recursion-limit-to-GRO.patch new file mode 100644 index 0000000..5bfe1df --- /dev/null +++ b/patches/cve/CVE-2016-7039-net-add-recursion-limit-to-GRO.patch @@ -0,0 +1,209 @@ +From fabaaaa96d54077b4a9f2c811e55dc09ff2874db Mon Sep 17 00:00:00 2001 +From: Sabrina Dubroca +Date: Wed, 14 Dec 2016 13:24:55 +0100 +Subject: [PATCH] net: add recursion limit to GRO +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Debian: net-add-recursion-limit-to-gro.patch ] + +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š for the initial bug report. + +Fixes: CVE-2016-7039 +Upstream-Status: Backport + +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 +Reviewed-by: Jiri Benc +Acked-by: Hannes Frederic Sowa +Signed-off-by: Philipp Hahn +Signed-off-by: Sasha Levin +Signed-off-by: Andreas Wellving +--- + drivers/net/vxlan.c | 2 +- + include/linux/netdevice.h | 24 +++++++++++++++++++++++- + 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 | 9 +++++++-- + net/ipv6/ip6_offload.c | 2 +- + 9 files changed, 38 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c +index 940f78e..d9e873c 100644 +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -635,7 +635,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, + } + } + +- pp = eth_gro_receive(head, skb); ++ pp = call_gro_receive(eth_gro_receive, head, skb); + + out: + skb_gro_remcsum_cleanup(skb, &grc); +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 6c86c7e..ddd47c3a 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1957,7 +1957,10 @@ struct napi_gro_cb { + /* Used in foo-over-udp, set in udp[46]_gro_receive */ + u8 is_ipv6:1; + +- /* 7 bit hole */ ++ /* Number of gro_receive callbacks this packet already went through */ ++ u8 recursion_counter:4; ++ ++ /* 3 bit hole */ + + /* used to support CHECKSUM_COMPLETE for tunneling protocols */ + __wsum csum; +@@ -1968,6 +1971,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 */ +diff --git a/net/core/dev.c b/net/core/dev.c +index 185a339..56d820f 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4060,6 +4060,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff + NAPI_GRO_CB(skb)->flush = 0; + NAPI_GRO_CB(skb)->free = 0; + NAPI_GRO_CB(skb)->udp_mark = 0; ++ NAPI_GRO_CB(skb)->recursion_counter = 0; + NAPI_GRO_CB(skb)->gro_remcsum_start = 0; + + /* Setup for GRO checksum validation */ +diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c +index f3bad41..76f8389 100644 +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -434,7 +434,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head, + + 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(); +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index 0cc98b1..2095cd6 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -1377,7 +1377,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, + 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(); +diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c +index 4b67937..b22a75c0 100644 +--- a/net/ipv4/fou.c ++++ b/net/ipv4/fou.c +@@ -188,7 +188,7 @@ static struct sk_buff **fou_gro_receive(struct sk_buff **head, + 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(); +@@ -355,7 +355,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, + if (WARN_ON(!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(); +diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c +index 5a8ee32..53300b8 100644 +--- a/net/ipv4/gre_offload.c ++++ b/net/ipv4/gre_offload.c +@@ -214,7 +214,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, + /* 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); + + out_unlock: + rcu_read_unlock(); +diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c +index f938616..2af7b7e 100644 +--- a/net/ipv4/udp_offload.c ++++ b/net/ipv4/udp_offload.c +@@ -339,8 +339,13 @@ unflush: + skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ + skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); + NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; +- pp = uo_priv->offload->callbacks.gro_receive(head, skb, +- uo_priv->offload); ++ ++ if (gro_recursion_inc_test(skb)) { ++ pp = NULL; ++ } else { ++ pp = uo_priv->offload->callbacks.gro_receive(head, skb, ++ uo_priv->offload); ++ } + + out_unlock: + rcu_read_unlock(); +diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c +index 08b6204..db0b842 100644 +--- a/net/ipv6/ip6_offload.c ++++ b/net/ipv6/ip6_offload.c +@@ -247,7 +247,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, + + 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(); +-- +2.7.4 + -- cgit v1.2.3-54-g00ecf