Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar...
[linux-2.6-microblaze.git] / kernel / nsproxy.c
index c815f58..ed98821 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pid_namespace.h>
 #include <net/net_namespace.h>
 #include <linux/ipc_namespace.h>
+#include <linux/time_namespace.h>
 #include <linux/proc_ns.h>
 #include <linux/file.h>
 #include <linux/syscalls.h>
@@ -40,6 +41,10 @@ struct nsproxy init_nsproxy = {
 #ifdef CONFIG_CGROUPS
        .cgroup_ns              = &init_cgroup_ns,
 #endif
+#ifdef CONFIG_TIME_NS
+       .time_ns                = &init_time_ns,
+       .time_ns_for_children   = &init_time_ns,
+#endif
 };
 
 static inline struct nsproxy *create_nsproxy(void)
@@ -106,8 +111,18 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
                goto out_net;
        }
 
+       new_nsp->time_ns_for_children = copy_time_ns(flags, user_ns,
+                                       tsk->nsproxy->time_ns_for_children);
+       if (IS_ERR(new_nsp->time_ns_for_children)) {
+               err = PTR_ERR(new_nsp->time_ns_for_children);
+               goto out_time;
+       }
+       new_nsp->time_ns = get_time_ns(tsk->nsproxy->time_ns);
+
        return new_nsp;
 
+out_time:
+       put_net(new_nsp->net_ns);
 out_net:
        put_cgroup_ns(new_nsp->cgroup_ns);
 out_cgroup:
@@ -136,15 +151,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        struct nsproxy *old_ns = tsk->nsproxy;
        struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
        struct nsproxy *new_ns;
+       int ret;
 
        if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
                              CLONE_NEWPID | CLONE_NEWNET |
-                             CLONE_NEWCGROUP)))) {
-               get_nsproxy(old_ns);
-               return 0;
-       }
-
-       if (!ns_capable(user_ns, CAP_SYS_ADMIN))
+                             CLONE_NEWCGROUP | CLONE_NEWTIME)))) {
+               if (likely(old_ns->time_ns_for_children == old_ns->time_ns)) {
+                       get_nsproxy(old_ns);
+                       return 0;
+               }
+       } else if (!ns_capable(user_ns, CAP_SYS_ADMIN))
                return -EPERM;
 
        /*
@@ -162,6 +178,12 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        if (IS_ERR(new_ns))
                return  PTR_ERR(new_ns);
 
+       ret = timens_on_fork(new_ns, tsk);
+       if (ret) {
+               free_nsproxy(new_ns);
+               return ret;
+       }
+
        tsk->nsproxy = new_ns;
        return 0;
 }
@@ -176,6 +198,10 @@ void free_nsproxy(struct nsproxy *ns)
                put_ipc_ns(ns->ipc_ns);
        if (ns->pid_ns_for_children)
                put_pid_ns(ns->pid_ns_for_children);
+       if (ns->time_ns)
+               put_time_ns(ns->time_ns);
+       if (ns->time_ns_for_children)
+               put_time_ns(ns->time_ns_for_children);
        put_cgroup_ns(ns->cgroup_ns);
        put_net(ns->net_ns);
        kmem_cache_free(nsproxy_cachep, ns);
@@ -192,7 +218,8 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
        int err = 0;
 
        if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                              CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP)))
+                              CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP |
+                              CLONE_NEWTIME)))
                return 0;
 
        user_ns = new_cred ? new_cred->user_ns : current_user_ns();