gre: fix netns vs proto registration ordering
authorAlexey Dobriyan <adobriyan@gmail.com>
Tue, 16 Feb 2010 07:57:44 +0000 (07:57 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Feb 2010 22:55:21 +0000 (14:55 -0800)
GRE protocol receive hook can be called right after protocol addition is done.
If netns stuff is not yet initialized, we're going to oops in
net_generic().

This is remotely oopsable if ip_gre is compiled as module and packet
comes at unfortunate moment of module loading.

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

index 7631b20..a2a5983 100644 (file)
@@ -1665,14 +1665,15 @@ static int __init ipgre_init(void)
 
        printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
 
-       if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
-               printk(KERN_INFO "ipgre init: can't add protocol\n");
-               return -EAGAIN;
-       }
-
        err = register_pernet_device(&ipgre_net_ops);
        if (err < 0)
-               goto gen_device_failed;
+               return err;
+
+       err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
+       if (err < 0) {
+               printk(KERN_INFO "ipgre init: can't add protocol\n");
+               goto add_proto_failed;
+       }
 
        err = rtnl_link_register(&ipgre_link_ops);
        if (err < 0)
@@ -1688,9 +1689,9 @@ out:
 tap_ops_failed:
        rtnl_link_unregister(&ipgre_link_ops);
 rtnl_link_failed:
-       unregister_pernet_device(&ipgre_net_ops);
-gen_device_failed:
        inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+add_proto_failed:
+       unregister_pernet_device(&ipgre_net_ops);
        goto out;
 }
 
@@ -1698,9 +1699,9 @@ static void __exit ipgre_fini(void)
 {
        rtnl_link_unregister(&ipgre_tap_ops);
        rtnl_link_unregister(&ipgre_link_ops);
-       unregister_pernet_device(&ipgre_net_ops);
        if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
                printk(KERN_INFO "ipgre close: can't remove protocol\n");
+       unregister_pernet_device(&ipgre_net_ops);
 }
 
 module_init(ipgre_init);