--- /dev/null
+From f44a5f45f544561302e855e7bd104e5f506ec01b Mon Sep 17 00:00:00 2001
+From: Peter Christensen <pch@ordbogen.com>
+Date: Sat, 24 May 2014 21:40:12 +0200
+Subject: ipvs: Fix panic due to non-linear skb
+
+From: Peter Christensen <pch@ordbogen.com>
+
+commit f44a5f45f544561302e855e7bd104e5f506ec01b upstream.
+
+Receiving a ICMP response to an IPIP packet in a non-linear skb could
+cause a kernel panic in __skb_pull.
+
+The problem was introduced in
+commit f2edb9f7706dcb2c0d9a362b2ba849efe3a97f5e ("ipvs: implement
+passive PMTUD for IPIP packets").
+
+Signed-off-by: Peter Christensen <pch@ordbogen.com>
+Acked-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Simon Horman <horms@verge.net.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/ipvs/ip_vs_core.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/net/netfilter/ipvs/ip_vs_core.c
++++ b/net/netfilter/ipvs/ip_vs_core.c
+@@ -1384,15 +1384,19 @@ ip_vs_in_icmp(struct sk_buff *skb, int *
+
+ if (ipip) {
+ __be32 info = ic->un.gateway;
++ __u8 type = ic->type;
++ __u8 code = ic->code;
+
+ /* Update the MTU */
+ if (ic->type == ICMP_DEST_UNREACH &&
+ ic->code == ICMP_FRAG_NEEDED) {
+ struct ip_vs_dest *dest = cp->dest;
+ u32 mtu = ntohs(ic->un.frag.mtu);
++ __be16 frag_off = cih->frag_off;
+
+ /* Strip outer IP and ICMP, go to IPIP header */
+- __skb_pull(skb, ihl + sizeof(_icmph));
++ if (pskb_pull(skb, ihl + sizeof(_icmph)) == NULL)
++ goto ignore_ipip;
+ offset2 -= ihl + sizeof(_icmph);
+ skb_reset_network_header(skb);
+ IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n",
+@@ -1400,7 +1404,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *
+ ipv4_update_pmtu(skb, dev_net(skb->dev),
+ mtu, 0, 0, 0, 0);
+ /* Client uses PMTUD? */
+- if (!(cih->frag_off & htons(IP_DF)))
++ if (!(frag_off & htons(IP_DF)))
+ goto ignore_ipip;
+ /* Prefer the resulting PMTU */
+ if (dest) {
+@@ -1419,12 +1423,13 @@ ip_vs_in_icmp(struct sk_buff *skb, int *
+ /* Strip outer IP, ICMP and IPIP, go to IP header of
+ * original request.
+ */
+- __skb_pull(skb, offset2);
++ if (pskb_pull(skb, offset2) == NULL)
++ goto ignore_ipip;
+ skb_reset_network_header(skb);
+ IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n",
+ &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr,
+- ic->type, ic->code, ntohl(info));
+- icmp_send(skb, ic->type, ic->code, info);
++ type, code, ntohl(info));
++ icmp_send(skb, type, code, info);
+ /* ICMP can be shorter but anyways, account it */
+ ip_vs_out_stats(cp, skb);
+