aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorxeb@mail.ru <xeb@mail.ru>2011-07-22 16:49:40 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-23 23:06:00 -0400
commit559fafb94ad9e4cd8774f39241917c57396f9fc5 (patch)
treef1c255fff42f8429ba3d17f4a7e19f1cc8cfe338 /net
parentb0fe4a31849063fcac0bdc93716ca92615e93f57 (diff)
gre: fix improper error handling
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>
Diffstat (limited to 'net')
-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 9dbe10875fbd..dbfc21de3479 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/spinlock.h> 20#include <linux/spinlock.h>
20#include <net/protocol.h> 21#include <net/protocol.h>
@@ -96,27 +97,17 @@ drop:
96static void gre_err(struct sk_buff *skb, u32 info) 97static void gre_err(struct sk_buff *skb, u32 info)
97{ 98{
98 const struct gre_protocol *proto; 99 const struct gre_protocol *proto;
99 u8 ver; 100 const struct iphdr *iph = (const struct iphdr *)skb->data;
100 101 u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
101 if (!pskb_may_pull(skb, 12))
102 goto drop;
103 102
104 ver = skb->data[1]&0x7f;
105 if (ver >= GREPROTO_MAX) 103 if (ver >= GREPROTO_MAX)
106 goto drop; 104 return;
107 105
108 rcu_read_lock(); 106 rcu_read_lock();
109 proto = rcu_dereference(gre_proto[ver]); 107 proto = rcu_dereference(gre_proto[ver]);
110 if (!proto || !proto->err_handler) 108 if (proto && proto->err_handler)
111 goto drop_unlock; 109 proto->err_handler(skb, info);
112 proto->err_handler(skb, info);
113 rcu_read_unlock();
114 return;
115
116drop_unlock:
117 rcu_read_unlock(); 110 rcu_read_unlock();
118drop:
119 kfree_skb(skb);
120} 111}
121 112
122static const struct net_protocol net_gre_protocol = { 113static const struct net_protocol net_gre_protocol = {