The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/nsproxy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  Copyright (C) 2006 IBM Corporation
    3  *
    4  *  Author: Serge Hallyn <serue@us.ibm.com>
    5  *
    6  *  This program is free software; you can redistribute it and/or
    7  *  modify it under the terms of the GNU General Public License as
    8  *  published by the Free Software Foundation, version 2 of the
    9  *  License.
   10  *
   11  *  Jun 2006 - namespaces support
   12  *             OpenVZ, SWsoft Inc.
   13  *             Pavel Emelianov <xemul@openvz.org>
   14  */
   15 
   16 #include <linux/slab.h>
   17 #include <linux/export.h>
   18 #include <linux/nsproxy.h>
   19 #include <linux/init_task.h>
   20 #include <linux/mnt_namespace.h>
   21 #include <linux/utsname.h>
   22 #include <linux/pid_namespace.h>
   23 #include <net/net_namespace.h>
   24 #include <linux/ipc_namespace.h>
   25 #include <linux/proc_fs.h>
   26 #include <linux/file.h>
   27 #include <linux/syscalls.h>
   28 
   29 static struct kmem_cache *nsproxy_cachep;
   30 
   31 struct nsproxy init_nsproxy = {
   32         .count  = ATOMIC_INIT(1),
   33         .uts_ns = &init_uts_ns,
   34 #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
   35         .ipc_ns = &init_ipc_ns,
   36 #endif
   37         .mnt_ns = NULL,
   38         .pid_ns = &init_pid_ns,
   39 #ifdef CONFIG_NET
   40         .net_ns = &init_net,
   41 #endif
   42 };
   43 
   44 static inline struct nsproxy *create_nsproxy(void)
   45 {
   46         struct nsproxy *nsproxy;
   47 
   48         nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
   49         if (nsproxy)
   50                 atomic_set(&nsproxy->count, 1);
   51         return nsproxy;
   52 }
   53 
   54 /*
   55  * Create new nsproxy and all of its the associated namespaces.
   56  * Return the newly created nsproxy.  Do not attach this to the task,
   57  * leave it to the caller to do proper locking and attach it to task.
   58  */
   59 static struct nsproxy *create_new_namespaces(unsigned long flags,
   60         struct task_struct *tsk, struct user_namespace *user_ns,
   61         struct fs_struct *new_fs)
   62 {
   63         struct nsproxy *new_nsp;
   64         int err;
   65 
   66         new_nsp = create_nsproxy();
   67         if (!new_nsp)
   68                 return ERR_PTR(-ENOMEM);
   69 
   70         new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
   71         if (IS_ERR(new_nsp->mnt_ns)) {
   72                 err = PTR_ERR(new_nsp->mnt_ns);
   73                 goto out_ns;
   74         }
   75 
   76         new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
   77         if (IS_ERR(new_nsp->uts_ns)) {
   78                 err = PTR_ERR(new_nsp->uts_ns);
   79                 goto out_uts;
   80         }
   81 
   82         new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
   83         if (IS_ERR(new_nsp->ipc_ns)) {
   84                 err = PTR_ERR(new_nsp->ipc_ns);
   85                 goto out_ipc;
   86         }
   87 
   88         new_nsp->pid_ns = copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns);
   89         if (IS_ERR(new_nsp->pid_ns)) {
   90                 err = PTR_ERR(new_nsp->pid_ns);
   91                 goto out_pid;
   92         }
   93 
   94         new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
   95         if (IS_ERR(new_nsp->net_ns)) {
   96                 err = PTR_ERR(new_nsp->net_ns);
   97                 goto out_net;
   98         }
   99 
  100         return new_nsp;
  101 
  102 out_net:
  103         if (new_nsp->pid_ns)
  104                 put_pid_ns(new_nsp->pid_ns);
  105 out_pid:
  106         if (new_nsp->ipc_ns)
  107                 put_ipc_ns(new_nsp->ipc_ns);
  108 out_ipc:
  109         if (new_nsp->uts_ns)
  110                 put_uts_ns(new_nsp->uts_ns);
  111 out_uts:
  112         if (new_nsp->mnt_ns)
  113                 put_mnt_ns(new_nsp->mnt_ns);
  114 out_ns:
  115         kmem_cache_free(nsproxy_cachep, new_nsp);
  116         return ERR_PTR(err);
  117 }
  118 
  119 /*
  120  * called from clone.  This now handles copy for nsproxy and all
  121  * namespaces therein.
  122  */
  123 int copy_namespaces(unsigned long flags, struct task_struct *tsk)
  124 {
  125         struct nsproxy *old_ns = tsk->nsproxy;
  126         struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
  127         struct nsproxy *new_ns;
  128         int err = 0;
  129 
  130         if (!old_ns)
  131                 return 0;
  132 
  133         get_nsproxy(old_ns);
  134 
  135         if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
  136                                 CLONE_NEWPID | CLONE_NEWNET)))
  137                 return 0;
  138 
  139         if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {
  140                 err = -EPERM;
  141                 goto out;
  142         }
  143 
  144         /*
  145          * CLONE_NEWIPC must detach from the undolist: after switching
  146          * to a new ipc namespace, the semaphore arrays from the old
  147          * namespace are unreachable.  In clone parlance, CLONE_SYSVSEM
  148          * means share undolist with parent, so we must forbid using
  149          * it along with CLONE_NEWIPC.
  150          */
  151         if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {
  152                 err = -EINVAL;
  153                 goto out;
  154         }
  155 
  156         new_ns = create_new_namespaces(flags, tsk,
  157                                        task_cred_xxx(tsk, user_ns), tsk->fs);
  158         if (IS_ERR(new_ns)) {
  159                 err = PTR_ERR(new_ns);
  160                 goto out;
  161         }
  162 
  163         tsk->nsproxy = new_ns;
  164 
  165 out:
  166         put_nsproxy(old_ns);
  167         return err;
  168 }
  169 
  170 void free_nsproxy(struct nsproxy *ns)
  171 {
  172         if (ns->mnt_ns)
  173                 put_mnt_ns(ns->mnt_ns);
  174         if (ns->uts_ns)
  175                 put_uts_ns(ns->uts_ns);
  176         if (ns->ipc_ns)
  177                 put_ipc_ns(ns->ipc_ns);
  178         if (ns->pid_ns)
  179                 put_pid_ns(ns->pid_ns);
  180         put_net(ns->net_ns);
  181         kmem_cache_free(nsproxy_cachep, ns);
  182 }
  183 
  184 /*
  185  * Called from unshare. Unshare all the namespaces part of nsproxy.
  186  * On success, returns the new nsproxy.
  187  */
  188 int unshare_nsproxy_namespaces(unsigned long unshare_flags,
  189         struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)
  190 {
  191         struct user_namespace *user_ns;
  192         int err = 0;
  193 
  194         if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
  195                                CLONE_NEWNET | CLONE_NEWPID)))
  196                 return 0;
  197 
  198         user_ns = new_cred ? new_cred->user_ns : current_user_ns();
  199         if (!ns_capable(user_ns, CAP_SYS_ADMIN))
  200                 return -EPERM;
  201 
  202         *new_nsp = create_new_namespaces(unshare_flags, current, user_ns,
  203                                          new_fs ? new_fs : current->fs);
  204         if (IS_ERR(*new_nsp)) {
  205                 err = PTR_ERR(*new_nsp);
  206                 goto out;
  207         }
  208 
  209 out:
  210         return err;
  211 }
  212 
  213 void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
  214 {
  215         struct nsproxy *ns;
  216 
  217         might_sleep();
  218 
  219         ns = p->nsproxy;
  220 
  221         rcu_assign_pointer(p->nsproxy, new);
  222 
  223         if (ns && atomic_dec_and_test(&ns->count)) {
  224                 /*
  225                  * wait for others to get what they want from this nsproxy.
  226                  *
  227                  * cannot release this nsproxy via the call_rcu() since
  228                  * put_mnt_ns() will want to sleep
  229                  */
  230                 synchronize_rcu();
  231                 free_nsproxy(ns);
  232         }
  233 }
  234 
  235 void exit_task_namespaces(struct task_struct *p)
  236 {
  237         switch_task_namespaces(p, NULL);
  238 }
  239 
  240 SYSCALL_DEFINE2(setns, int, fd, int, nstype)
  241 {
  242         const struct proc_ns_operations *ops;
  243         struct task_struct *tsk = current;
  244         struct nsproxy *new_nsproxy;
  245         struct proc_inode *ei;
  246         struct file *file;
  247         int err;
  248 
  249         file = proc_ns_fget(fd);
  250         if (IS_ERR(file))
  251                 return PTR_ERR(file);
  252 
  253         err = -EINVAL;
  254         ei = PROC_I(file->f_dentry->d_inode);
  255         ops = ei->ns_ops;
  256         if (nstype && (ops->type != nstype))
  257                 goto out;
  258 
  259         new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
  260         if (IS_ERR(new_nsproxy)) {
  261                 err = PTR_ERR(new_nsproxy);
  262                 goto out;
  263         }
  264 
  265         err = ops->install(new_nsproxy, ei->ns);
  266         if (err) {
  267                 free_nsproxy(new_nsproxy);
  268                 goto out;
  269         }
  270         switch_task_namespaces(tsk, new_nsproxy);
  271 out:
  272         fput(file);
  273         return err;
  274 }
  275 
  276 int __init nsproxy_cache_init(void)
  277 {
  278         nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
  279         return 0;
  280 }

Cache object: 2781881f292e41b7af9372b4098be2e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.