summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorxeb@mail.ru <xeb@mail.ru>2011-07-22 20:49:40 +0000
committerDavid S. Miller <davem@davemloft.net>2011-07-23 20:06:00 -0700
commit559fafb94ad9e4cd8774f39241917c57396f9fc5 (patch)
treef1c255fff42f8429ba3d17f4a7e19f1cc8cfe338 /net
parentb0fe4a31849063fcac0bdc93716ca92615e93f57 (diff)
downloadlinux-559fafb94ad9e4cd8774f39241917c57396f9fc5.tar.bz2
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 @@
#include <linux/kmod.h>
#include <linux/skbuff.h>
#include <linux/in.h>
+#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <net/protocol.h>
@@ -96,27 +97,17 @@ drop:
static void gre_err(struct sk_buff *skb, u32 info)
{
const struct gre_protocol *proto;
- u8 ver;
-
- if (!pskb_may_pull(skb, 12))
- goto drop;
+ const struct iphdr *iph = (const struct iphdr *)skb->data;
+ u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
- ver = skb->data[1]&0x7f;
if (ver >= GREPROTO_MAX)
- goto drop;
+ return;
rcu_read_lock();
proto = rcu_dereference(gre_proto[ver]);
- if (!proto || !proto->err_handler)
- goto drop_unlock;
- proto->err_handler(skb, info);
- rcu_read_unlock();
- return;
-
-drop_unlock:
+ if (proto && proto->err_handler)
+ proto->err_handler(skb, info);
rcu_read_unlock();
-drop:
- kfree_skb(skb);
}
static const struct net_protocol net_gre_protocol = {