aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorxeb@mail.ru <xeb@mail.ru>2011-07-22 16:49:40 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-15 21:31:39 -0400
commit06e67267adf0e3b9a25a78250a1c7caefd36f843 (patch)
treee3a3f7129a0bd38662e5ff6b3e42732a468443fd /net/ipv4
parentcb737cb02933192dcbb141480e3dc8153b89be48 (diff)
gre: fix improper error handling
[ Upstream commit 559fafb94ad9e4cd8774f39241917c57396f9fc5 ] Fix improper protocol err_handler, current implementation is fully unapplicable and may cause kernel crash due to double kfree_skb. Signed-off-by: Dmitry Kozlov <xeb@mail.ru> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/gre.c21
1 files changed, 6 insertions, 15 deletions
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index c6933f2ea31..3e3f75d96be 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -15,6 +15,7 @@
15#include <linux/kmod.h> 15#include <linux/kmod.h>
16#include <linux/skbuff.h> 16#include <linux/skbuff.h>
17#include <linux/in.h> 17#include <linux/in.h>
18#include <linux/ip.h>
18#include <linux/netdevice.h> 19#include <linux/netdevice.h>
19#include <linux/version.h> 20#include <linux/version.h>
20#include <linux/spinlock.h> 21#include <linux/spinlock.h>
@@ -97,27 +98,17 @@ drop:
97static void gre_err(struct sk_buff *skb, u32 info) 98static void gre_err(struct sk_buff *skb, u32 info)
98{ 99{
99 const struct gre_protocol *proto; 100 const struct gre_protocol *proto;
100 u8 ver; 101 const struct iphdr *iph = (const struct iphdr *)skb->data;
101 102 u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
102 if (!pskb_may_pull(skb, 12))
103 goto drop;
104 103
105 ver = skb->data[1]&0x7f;
106 if (ver >= GREPROTO_MAX) 104 if (ver >= GREPROTO_MAX)
107 goto drop; 105 return;
108 106
109 rcu_read_lock(); 107 rcu_read_lock();
110 proto = rcu_dereference(gre_proto[ver]); 108 proto = rcu_dereference(gre_proto[ver]);
111 if (!proto || !proto->err_handler) 109 if (proto && proto->err_handler)
112 goto drop_unlock; 110 proto->err_handler(skb, info);
113 proto->err_handler(skb, info);
114 rcu_read_unlock();
115 return;
116
117drop_unlock:
118 rcu_read_unlock(); 111 rcu_read_unlock();
119drop:
120 kfree_skb(skb);
121} 112}
122 113
123static const struct net_protocol net_gre_protocol = { 114static const struct net_protocol net_gre_protocol = {