diff options
| author | xeb@mail.ru <xeb@mail.ru> | 2011-07-22 16:49:40 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-15 21:31:39 -0400 |
| commit | 06e67267adf0e3b9a25a78250a1c7caefd36f843 (patch) | |
| tree | e3a3f7129a0bd38662e5ff6b3e42732a468443fd /net/ipv4 | |
| parent | cb737cb02933192dcbb141480e3dc8153b89be48 (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.c | 21 |
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: | |||
| 97 | static void gre_err(struct sk_buff *skb, u32 info) | 98 | static 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 | |||
| 117 | drop_unlock: | ||
| 118 | rcu_read_unlock(); | 111 | rcu_read_unlock(); |
| 119 | drop: | ||
| 120 | kfree_skb(skb); | ||
| 121 | } | 112 | } |
| 122 | 113 | ||
| 123 | static const struct net_protocol net_gre_protocol = { | 114 | static const struct net_protocol net_gre_protocol = { |
