]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/core/net_namespace.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[karo-tx-linux.git] / net / core / net_namespace.c
index 42f1e1c7514f67ad56df06ffe53e6c94a094681a..2e9a3132b8dd11ac8a9851e8042d8982af9c20ef 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/proc_fs.h>
 #include <linux/file.h>
 #include <linux/export.h>
+#include <linux/user_namespace.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -145,7 +146,7 @@ static void ops_free_list(const struct pernet_operations *ops,
 /*
  * setup_net runs the initializers for the network namespace object.
  */
-static __net_init int setup_net(struct net *net)
+static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
 {
        /* Must be called with net_mutex held */
        const struct pernet_operations *ops, *saved_ops;
@@ -155,6 +156,7 @@ static __net_init int setup_net(struct net *net)
        atomic_set(&net->count, 1);
        atomic_set(&net->passive, 1);
        net->dev_base_seq = 1;
+       net->user_ns = user_ns;
 
 #ifdef NETNS_REFCNT_DEBUG
        atomic_set(&net->use_count, 0);
@@ -232,7 +234,8 @@ void net_drop_ns(void *p)
                net_free(ns);
 }
 
-struct net *copy_net_ns(unsigned long flags, struct net *old_net)
+struct net *copy_net_ns(unsigned long flags,
+                       struct user_namespace *user_ns, struct net *old_net)
 {
        struct net *net;
        int rv;
@@ -243,8 +246,11 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
        net = net_alloc();
        if (!net)
                return ERR_PTR(-ENOMEM);
+
+       get_user_ns(user_ns);
+
        mutex_lock(&net_mutex);
-       rv = setup_net(net);
+       rv = setup_net(net, user_ns);
        if (rv == 0) {
                rtnl_lock();
                list_add_tail_rcu(&net->list, &net_namespace_list);
@@ -252,6 +258,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
        }
        mutex_unlock(&net_mutex);
        if (rv < 0) {
+               put_user_ns(user_ns);
                net_drop_ns(net);
                return ERR_PTR(rv);
        }
@@ -308,6 +315,7 @@ static void cleanup_net(struct work_struct *work)
        /* Finally it is safe to free my network namespace structure */
        list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
                list_del_init(&net->exit_list);
+               put_user_ns(net->user_ns);
                net_drop_ns(net);
        }
 }
@@ -347,13 +355,6 @@ struct net *get_net_ns_by_fd(int fd)
 }
 
 #else
-struct net *copy_net_ns(unsigned long flags, struct net *old_net)
-{
-       if (flags & CLONE_NEWNET)
-               return ERR_PTR(-EINVAL);
-       return old_net;
-}
-
 struct net *get_net_ns_by_fd(int fd)
 {
        return ERR_PTR(-EINVAL);
@@ -380,6 +381,21 @@ struct net *get_net_ns_by_pid(pid_t pid)
 }
 EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
 
+static __net_init int net_ns_net_init(struct net *net)
+{
+       return proc_alloc_inum(&net->proc_inum);
+}
+
+static __net_exit void net_ns_net_exit(struct net *net)
+{
+       proc_free_inum(net->proc_inum);
+}
+
+static struct pernet_operations __net_initdata net_ns_ops = {
+       .init = net_ns_net_init,
+       .exit = net_ns_net_exit,
+};
+
 static int __init net_ns_init(void)
 {
        struct net_generic *ng;
@@ -402,7 +418,7 @@ static int __init net_ns_init(void)
        rcu_assign_pointer(init_net.gen, ng);
 
        mutex_lock(&net_mutex);
-       if (setup_net(&init_net))
+       if (setup_net(&init_net, &init_user_ns))
                panic("Could not setup the initial network namespace");
 
        rtnl_lock();
@@ -411,6 +427,8 @@ static int __init net_ns_init(void)
 
        mutex_unlock(&net_mutex);
 
+       register_pernet_subsys(&net_ns_ops);
+
        return 0;
 }
 
@@ -629,16 +647,28 @@ static void netns_put(void *ns)
 
 static int netns_install(struct nsproxy *nsproxy, void *ns)
 {
+       struct net *net = ns;
+
+       if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
        put_net(nsproxy->net_ns);
-       nsproxy->net_ns = get_net(ns);
+       nsproxy->net_ns = get_net(net);
        return 0;
 }
 
+static unsigned int netns_inum(void *ns)
+{
+       struct net *net = ns;
+       return net->proc_inum;
+}
+
 const struct proc_ns_operations netns_operations = {
        .name           = "net",
        .type           = CLONE_NEWNET,
        .get            = netns_get,
        .put            = netns_put,
        .install        = netns_install,
+       .inum           = netns_inum,
 };
 #endif