pidns: Add setns support
authorEric W. Biederman <ebiederm@xmission.com>
Mon, 8 Mar 2010 02:17:03 +0000 (18:17 -0800)
committerEric W. Biederman <ebiederm@xmission.com>
Mon, 19 Nov 2012 13:59:14 +0000 (05:59 -0800)
- Pid namespaces are designed to be inescapable so verify that the
  passed in pid namespace is a child of the currently active
  pid namespace or the currently active pid namespace itself.

  Allowing the currently active pid namespace is important so
  the effects of an earlier setns can be cancelled.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
fs/proc/namespaces.c
include/linux/proc_fs.h
kernel/pid_namespace.c

index b178ed733c3698a0ad2fcf49def0727b9fc135f6..85ca047e35f135e7b012da336e88c41137591faf 100644 (file)
@@ -24,6 +24,9 @@ static const struct proc_ns_operations *ns_entries[] = {
 #ifdef CONFIG_IPC_NS
        &ipcns_operations,
 #endif
+#ifdef CONFIG_PID_NS
+       &pidns_operations,
+#endif
 };
 
 static const struct file_operations ns_file_operations = {
index 3fd2e871ff1bfbd23fae57c536d8b247c19ef131..acaafcd40aa5607d37d687001e84e6ddceb3de3e 100644 (file)
@@ -251,6 +251,7 @@ struct proc_ns_operations {
 extern const struct proc_ns_operations netns_operations;
 extern const struct proc_ns_operations utsns_operations;
 extern const struct proc_ns_operations ipcns_operations;
+extern const struct proc_ns_operations pidns_operations;
 
 union proc_op {
        int (*proc_get_link)(struct dentry *, struct path *);
index 0dbbc66b6ec6b1e6322ac1b3904522afe68d327e..f78fc48c86bc9fbff34c093df7a8251140ad38b1 100644 (file)
@@ -301,6 +301,60 @@ int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
        return 0;
 }
 
+static void *pidns_get(struct task_struct *task)
+{
+       struct pid_namespace *ns;
+
+       rcu_read_lock();
+       ns = get_pid_ns(task_active_pid_ns(task));
+       rcu_read_unlock();
+
+       return ns;
+}
+
+static void pidns_put(void *ns)
+{
+       put_pid_ns(ns);
+}
+
+static int pidns_install(struct nsproxy *nsproxy, void *ns)
+{
+       struct pid_namespace *active = task_active_pid_ns(current);
+       struct pid_namespace *ancestor, *new = ns;
+
+       if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /*
+        * Only allow entering the current active pid namespace
+        * or a child of the current active pid namespace.
+        *
+        * This is required for fork to return a usable pid value and
+        * this maintains the property that processes and their
+        * children can not escape their current pid namespace.
+        */
+       if (new->level < active->level)
+               return -EINVAL;
+
+       ancestor = new;
+       while (ancestor->level > active->level)
+               ancestor = ancestor->parent;
+       if (ancestor != active)
+               return -EINVAL;
+
+       put_pid_ns(nsproxy->pid_ns);
+       nsproxy->pid_ns = get_pid_ns(new);
+       return 0;
+}
+
+const struct proc_ns_operations pidns_operations = {
+       .name           = "pid",
+       .type           = CLONE_NEWPID,
+       .get            = pidns_get,
+       .put            = pidns_put,
+       .install        = pidns_install,
+};
+
 static __init int pid_namespaces_init(void)
 {
        pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC);