From c3c0fe0e2bf0b3cbdae4751fb6c708f36fca0c18 Mon Sep 17 00:00:00 2001
From: Alexey Dobriyan <adobriyan@gmail.com>
Date: Tue, 16 Feb 2010 09:05:04 +0000
Subject: [PATCH] tunnels: fix netns vs proto registration ordering

Same stuff as in ip_gre patch: receive hook can be called before netns
setup is done, oopsing in net_generic().

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

[Also includes fixed for openvz patch kit following this change.]
(backported from commit d5aa407f59f5b83d2c50ec88f5bf56d40f1f8978)
CVE-2011-1768
BugLink: http://bugs.launchpad.net/bugs/869215
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 .../openvz/patchset/0001-2.6.24-ovz002.patch       |   32 ++++++------------
 net/ipv4/ipip.c                                    |   18 ++++++-----
 net/ipv6/ip6_tunnel.c                              |   33 ++++++++++---------
 net/ipv6/sit.c                                     |   19 ++++++-----
 net/ipv6/xfrm6_tunnel.c                            |   18 +++++-----
 5 files changed, 57 insertions(+), 63 deletions(-)

diff --git a/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch b/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch
index 6a8a613..b5025b8 100644
--- a/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch
+++ b/debian/binary-custom.d/openvz/patchset/0001-2.6.24-ovz002.patch
@@ -87076,46 +87076,36 @@ Index: kernel/net/ipv6/sit.c
  }
  
  static int __init sit_init(void)
-@@ -832,23 +944,35 @@
- 		return -EAGAIN;
- 	}
+@@ -827,11 +939,17 @@ static int __init sit_init(void)
+ 
+ 	printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
  
 +#ifdef CONFIG_VE
 +	err = sit_ve_start(get_exec_env());
 +	if (err)
-+		goto err1;
++		goto out;
 +#endif
 +
  	ipip6_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0",
  					   ipip6_tunnel_setup);
  	if (!ipip6_fb_tunnel_dev) {
  		err = -ENOMEM;
--		goto err1;
-+		goto err2;
+-		goto out;
++		goto err0;
  	}
  
  	ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init;
- 
- 	if ((err =  register_netdev(ipip6_fb_tunnel_dev)))
--		goto err2;
-+		goto err3;
-+
-+	ve_hook_register(VE_SS_CHAIN, &sit_ve_hook);
- 
-  out:
- 	return err;
-- err2:
-+ err3:
+@@ -851,6 +969,10 @@ static int __init sit_init(void)
+ 	unregister_netdev(ipip6_fb_tunnel_dev);
+  err1:
  	free_netdev(ipip6_fb_tunnel_dev);
-- err1:
-+ err2:
++ err0:
 +#ifdef CONFIG_VE
 +	sit_ve_stop(get_exec_env());
-+err1:
 +#endif
- 	xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
  	goto out;
  }
+ 
 Index: kernel/net/ipv6/tcp_ipv6.c
 ===================================================================
 --- kernel.orig/net/ipv6/tcp_ipv6.c	2008-11-18 01:19:47.000000000 +0100
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 8c2b2b0..44446fd 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -863,29 +863,31 @@ static int __init ipip_init(void)
 
 	printk(banner);
 
-	if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) {
-		printk(KERN_INFO "ipip init: can't register tunnel\n");
-		return -EAGAIN;
-	}
-
 	ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
 					   "tunl0",
 					   ipip_tunnel_setup);
 	if (!ipip_fb_tunnel_dev) {
 		err = -ENOMEM;
-		goto err1;
+		goto out;
 	}
 
 	ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init;
 
 	if ((err = register_netdev(ipip_fb_tunnel_dev)))
+		goto err1;
+
+	if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) {
+		printk(KERN_INFO "ipip init: can't register tunnel\n");
+		err = -EAGAIN;
 		goto err2;
+	}
+
  out:
 	return err;
  err2:
-	free_netdev(ipip_fb_tunnel_dev);
+	unregister_netdev(ipip_fb_tunnel_dev);
  err1:
-	xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
+	free_netdev(ipip_fb_tunnel_dev);
 	goto out;
 }
 
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 81941a1..c4e3dd0 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1396,10 +1396,22 @@ static int __init ip6_tunnel_init(void)
 {
 	int  err;
 
+	ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
+				      ip6_tnl_dev_setup);
+	if (!ip6_fb_tnl_dev) {
+		err = -ENOMEM;
+		goto out;
+	}
+	ip6_fb_tnl_dev->init = ip6_fb_tnl_dev_init;
+
+	if ((err = register_netdev(ip6_fb_tnl_dev))) {
+		goto free_netdev;
+	}
+
 	if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) {
 		printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n");
 		err = -EAGAIN;
-		goto out;
+		goto unreg_netdev;
 	}
 
 	if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
@@ -1407,24 +1419,13 @@ static int __init ip6_tunnel_init(void)
 		err = -EAGAIN;
 		goto unreg_ip4ip6;
 	}
-	ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
-				      ip6_tnl_dev_setup);
-
-	if (!ip6_fb_tnl_dev) {
-		err = -ENOMEM;
-		goto fail;
-	}
-	ip6_fb_tnl_dev->init = ip6_fb_tnl_dev_init;
-
-	if ((err = register_netdev(ip6_fb_tnl_dev))) {
-		free_netdev(ip6_fb_tnl_dev);
-		goto fail;
-	}
 	return 0;
-fail:
-	xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
 unreg_ip4ip6:
 	xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
+unreg_netdev:
+	unregister_netdev(ip6_fb_tnl_dev);
+free_netdev:
+	free_netdev(ip6_fb_tnl_dev);
 out:
 	return err;
 }
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index bd22f64..3e2ce4a 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -827,29 +827,30 @@ static int __init sit_init(void)
 
 	printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
 
-	if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) {
-		printk(KERN_INFO "sit init: Can't add protocol\n");
-		return -EAGAIN;
-	}
-
 	ipip6_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0",
 					   ipip6_tunnel_setup);
 	if (!ipip6_fb_tunnel_dev) {
 		err = -ENOMEM;
-		goto err1;
+		goto out;
 	}
 
 	ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init;
 
-	if ((err =  register_netdev(ipip6_fb_tunnel_dev)))
+	if ((err = register_netdev(ipip6_fb_tunnel_dev)))
+		goto err1;
+
+	if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) {
+		printk(KERN_INFO "sit init: Can't add protocol\n");
+		err = -EAGAIN;
 		goto err2;
+	}
 
  out:
 	return err;
  err2:
-	free_netdev(ipip6_fb_tunnel_dev);
+	unregister_netdev(ipip6_fb_tunnel_dev);
  err1:
-	xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
+	free_netdev(ipip6_fb_tunnel_dev);
 	goto out;
 }
 
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index fae90ff..556491b 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -343,22 +343,22 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = {
 
 static int __init xfrm6_tunnel_init(void)
 {
-	if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0)
+	if (xfrm6_tunnel_spi_init() < 0)
 		return -EAGAIN;
-
-	if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) {
-		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+		
+	if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) {
+		xfrm6_tunnel_spi_fini();
 		return -EAGAIN;
 	}
-	if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) {
-		xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
+	if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) {
 		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+		xfrm6_tunnel_spi_fini();
 		return -EAGAIN;
 	}
-	if (xfrm6_tunnel_spi_init() < 0) {
-		xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
+	if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) {
 		xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
 		xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+		xfrm6_tunnel_spi_fini();
 		return -EAGAIN;
 	}
 	return 0;
@@ -366,10 +366,10 @@ static int __init xfrm6_tunnel_init(void)
 
 static void __exit xfrm6_tunnel_fini(void)
 {
-	xfrm6_tunnel_spi_fini();
 	xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
 	xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
 	xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+	xfrm6_tunnel_spi_fini();
 }
 
 module_init(xfrm6_tunnel_init);
-- 
1.7.5.4

