LCOV - code coverage report
Current view: top level - kernel - nsproxy.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 77 79.2 %
Date: 2014-04-07 Functions: 7 8 87.5 %
Branches: 33 50 66.0 %

           Branch data     Line data    Source code
       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_ns.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_for_children    = &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                 :          6 :         nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
      49         [ +  - ]:          6 :         if (nsproxy)
      50                 :          6 :                 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                 :          0 : 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         [ +  - ]:          6 :         if (!new_nsp)
      68                 :            :                 return ERR_PTR(-ENOMEM);
      69                 :            : 
      70                 :          6 :         new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
      71         [ -  + ]:         12 :         if (IS_ERR(new_nsp->mnt_ns)) {
      72                 :            :                 err = PTR_ERR(new_nsp->mnt_ns);
      73                 :          0 :                 goto out_ns;
      74                 :            :         }
      75                 :            : 
      76                 :         18 :         new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
      77         [ +  + ]:         12 :         if (IS_ERR(new_nsp->uts_ns)) {
      78                 :            :                 err = PTR_ERR(new_nsp->uts_ns);
      79                 :          1 :                 goto out_uts;
      80                 :            :         }
      81                 :            : 
      82                 :         10 :         new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
      83         [ +  + ]:          5 :         if (IS_ERR(new_nsp->ipc_ns)) {
      84                 :            :                 err = PTR_ERR(new_nsp->ipc_ns);
      85                 :          2 :                 goto out_ipc;
      86                 :            :         }
      87                 :            : 
      88                 :          3 :         new_nsp->pid_ns_for_children =
      89                 :          3 :                 copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
      90         [ +  + ]:          3 :         if (IS_ERR(new_nsp->pid_ns_for_children)) {
      91                 :            :                 err = PTR_ERR(new_nsp->pid_ns_for_children);
      92                 :          1 :                 goto out_pid;
      93                 :            :         }
      94                 :            : 
      95                 :          4 :         new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
      96         [ -  + ]:          2 :         if (IS_ERR(new_nsp->net_ns)) {
      97                 :            :                 err = PTR_ERR(new_nsp->net_ns);
      98                 :            :                 goto out_net;
      99                 :            :         }
     100                 :            : 
     101                 :            :         return new_nsp;
     102                 :            : 
     103                 :            : out_net:
     104                 :            :         if (new_nsp->pid_ns_for_children)
     105                 :            :                 put_pid_ns(new_nsp->pid_ns_for_children);
     106                 :            : out_pid:
     107                 :            :         if (new_nsp->ipc_ns)
     108                 :            :                 put_ipc_ns(new_nsp->ipc_ns);
     109                 :            : out_ipc:
     110                 :            :         if (new_nsp->uts_ns)
     111                 :            :                 put_uts_ns(new_nsp->uts_ns);
     112                 :            : out_uts:
     113         [ +  - ]:          4 :         if (new_nsp->mnt_ns)
     114                 :          4 :                 put_mnt_ns(new_nsp->mnt_ns);
     115                 :            : out_ns:
     116                 :          4 :         kmem_cache_free(nsproxy_cachep, new_nsp);
     117                 :          4 :         return ERR_PTR(err);
     118                 :            : }
     119                 :            : 
     120                 :            : /*
     121                 :            :  * called from clone.  This now handles copy for nsproxy and all
     122                 :            :  * namespaces therein.
     123                 :            :  */
     124                 :          0 : int copy_namespaces(unsigned long flags, struct task_struct *tsk)
     125                 :            : {
     126                 :    1122987 :         struct nsproxy *old_ns = tsk->nsproxy;
     127                 :    1122987 :         struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
     128                 :            :         struct nsproxy *new_ns;
     129                 :            : 
     130         [ +  + ]:    1122988 :         if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
     131                 :            :                               CLONE_NEWPID | CLONE_NEWNET)))) {
     132                 :            :                 get_nsproxy(old_ns);
     133                 :    1122984 :                 return 0;
     134                 :            :         }
     135                 :            : 
     136         [ +  - ]:          4 :         if (!ns_capable(user_ns, CAP_SYS_ADMIN))
     137                 :            :                 return -EPERM;
     138                 :            : 
     139                 :            :         /*
     140                 :            :          * CLONE_NEWIPC must detach from the undolist: after switching
     141                 :            :          * to a new ipc namespace, the semaphore arrays from the old
     142                 :            :          * namespace are unreachable.  In clone parlance, CLONE_SYSVSEM
     143                 :            :          * means share undolist with parent, so we must forbid using
     144                 :            :          * it along with CLONE_NEWIPC.
     145                 :            :          */
     146         [ +  - ]:          4 :         if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
     147                 :            :                 (CLONE_NEWIPC | CLONE_SYSVSEM)) 
     148                 :            :                 return -EINVAL;
     149                 :            : 
     150                 :          4 :         new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
     151         [ +  - ]:    1122991 :         if (IS_ERR(new_ns))
     152                 :          4 :                 return  PTR_ERR(new_ns);
     153                 :            : 
     154                 :          0 :         tsk->nsproxy = new_ns;
     155                 :          0 :         return 0;
     156                 :            : }
     157                 :            : 
     158                 :          0 : void free_nsproxy(struct nsproxy *ns)
     159                 :            : {
     160         [ +  - ]:          2 :         if (ns->mnt_ns)
     161                 :          2 :                 put_mnt_ns(ns->mnt_ns);
     162                 :            :         if (ns->uts_ns)
     163                 :            :                 put_uts_ns(ns->uts_ns);
     164                 :            :         if (ns->ipc_ns)
     165                 :            :                 put_ipc_ns(ns->ipc_ns);
     166                 :            :         if (ns->pid_ns_for_children)
     167                 :            :                 put_pid_ns(ns->pid_ns_for_children);
     168                 :            :         put_net(ns->net_ns);
     169                 :          2 :         kmem_cache_free(nsproxy_cachep, ns);
     170                 :          2 : }
     171                 :            : 
     172                 :            : /*
     173                 :            :  * Called from unshare. Unshare all the namespaces part of nsproxy.
     174                 :            :  * On success, returns the new nsproxy.
     175                 :            :  */
     176                 :          0 : int unshare_nsproxy_namespaces(unsigned long unshare_flags,
     177                 :            :         struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)
     178                 :            : {
     179                 :            :         struct user_namespace *user_ns;
     180                 :            :         int err = 0;
     181                 :            : 
     182         [ +  + ]:          5 :         if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
     183                 :            :                                CLONE_NEWNET | CLONE_NEWPID)))
     184                 :            :                 return 0;
     185                 :            : 
     186         [ -  + ]:          1 :         user_ns = new_cred ? new_cred->user_ns : current_user_ns();
     187         [ +  - ]:          1 :         if (!ns_capable(user_ns, CAP_SYS_ADMIN))
     188                 :            :                 return -EPERM;
     189                 :            : 
     190         [ +  - ]:          1 :         *new_nsp = create_new_namespaces(unshare_flags, current, user_ns,
     191                 :          1 :                                          new_fs ? new_fs : current->fs);
     192         [ -  + ]:          6 :         if (IS_ERR(*new_nsp)) {
     193                 :            :                 err = PTR_ERR(*new_nsp);
     194                 :          0 :                 goto out;
     195                 :            :         }
     196                 :            : 
     197                 :            : out:
     198                 :          1 :         return err;
     199                 :            : }
     200                 :            : 
     201                 :          0 : void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
     202                 :            : {
     203                 :            :         struct nsproxy *ns;
     204                 :            : 
     205                 :            :         might_sleep();
     206                 :            : 
     207                 :    1122974 :         ns = p->nsproxy;
     208                 :            : 
     209                 :    1122974 :         rcu_assign_pointer(p->nsproxy, new);
     210                 :            : 
     211   [ +  -  +  + ]:    2245919 :         if (ns && atomic_dec_and_test(&ns->count)) {
     212                 :            :                 /*
     213                 :            :                  * wait for others to get what they want from this nsproxy.
     214                 :            :                  *
     215                 :            :                  * cannot release this nsproxy via the call_rcu() since
     216                 :            :                  * put_mnt_ns() will want to sleep
     217                 :            :                  */
     218                 :            :                 synchronize_rcu();
     219                 :          1 :                 free_nsproxy(ns);
     220                 :            :         }
     221                 :          0 : }
     222                 :            : 
     223                 :          0 : void exit_task_namespaces(struct task_struct *p)
     224                 :            : {
     225                 :    1122977 :         switch_task_namespaces(p, NULL);
     226                 :    1122964 : }
     227                 :            : 
     228                 :          0 : SYSCALL_DEFINE2(setns, int, fd, int, nstype)
     229                 :            : {
     230                 :            :         const struct proc_ns_operations *ops;
     231                 :          6 :         struct task_struct *tsk = current;
     232                 :            :         struct nsproxy *new_nsproxy;
     233                 :            :         struct proc_ns *ei;
     234                 :          2 :         struct file *file;
     235                 :            :         int err;
     236                 :            : 
     237                 :          6 :         file = proc_ns_fget(fd);
     238         [ +  + ]:          6 :         if (IS_ERR(file))
     239                 :            :                 return PTR_ERR(file);
     240                 :            : 
     241                 :            :         err = -EINVAL;
     242                 :          2 :         ei = get_proc_ns(file_inode(file));
     243                 :          2 :         ops = ei->ns_ops;
     244 [ +  - ][ +  + ]:          2 :         if (nstype && (ops->type != nstype))
     245                 :            :                 goto out;
     246                 :            : 
     247                 :          1 :         new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
     248         [ -  + ]:          7 :         if (IS_ERR(new_nsproxy)) {
     249                 :            :                 err = PTR_ERR(new_nsproxy);
     250                 :            :                 goto out;
     251                 :            :         }
     252                 :            : 
     253                 :          1 :         err = ops->install(new_nsproxy, ei->ns);
     254         [ +  - ]:          1 :         if (err) {
     255                 :          1 :                 free_nsproxy(new_nsproxy);
     256                 :            :                 goto out;
     257                 :            :         }
     258                 :          0 :         switch_task_namespaces(tsk, new_nsproxy);
     259                 :            : out:
     260                 :          2 :         fput(file);
     261                 :            :         return err;
     262                 :            : }
     263                 :            : 
     264                 :          0 : int __init nsproxy_cache_init(void)
     265                 :            : {
     266                 :          0 :         nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
     267                 :          0 :         return 0;
     268                 :            : }

Generated by: LCOV version 1.9