LCOV - code coverage report
Current view: top level - kernel - nsproxy.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 86 45.3 %
Date: 2015-04-12 14:34:49 Functions: 6 8 75.0 %

          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           1 :         nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
      49           1 :         if (nsproxy)
      50           1 :                 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           1 : 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           1 :         if (!new_nsp)
      68             :                 return ERR_PTR(-ENOMEM);
      69             : 
      70           1 :         new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
      71           1 :         if (IS_ERR(new_nsp->mnt_ns)) {
      72             :                 err = PTR_ERR(new_nsp->mnt_ns);
      73           0 :                 goto out_ns;
      74             :         }
      75             : 
      76           1 :         new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
      77           1 :         if (IS_ERR(new_nsp->uts_ns)) {
      78             :                 err = PTR_ERR(new_nsp->uts_ns);
      79           0 :                 goto out_uts;
      80             :         }
      81             : 
      82           1 :         new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
      83           1 :         if (IS_ERR(new_nsp->ipc_ns)) {
      84             :                 err = PTR_ERR(new_nsp->ipc_ns);
      85           0 :                 goto out_ipc;
      86             :         }
      87             : 
      88           1 :         new_nsp->pid_ns_for_children =
      89           1 :                 copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
      90           1 :         if (IS_ERR(new_nsp->pid_ns_for_children)) {
      91             :                 err = PTR_ERR(new_nsp->pid_ns_for_children);
      92           0 :                 goto out_pid;
      93             :         }
      94             : 
      95           1 :         new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
      96           1 :         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           0 :         if (new_nsp->pid_ns_for_children)
     105           0 :                 put_pid_ns(new_nsp->pid_ns_for_children);
     106             : out_pid:
     107           0 :         if (new_nsp->ipc_ns)
     108           0 :                 put_ipc_ns(new_nsp->ipc_ns);
     109             : out_ipc:
     110           0 :         if (new_nsp->uts_ns)
     111             :                 put_uts_ns(new_nsp->uts_ns);
     112             : out_uts:
     113           0 :         if (new_nsp->mnt_ns)
     114           0 :                 put_mnt_ns(new_nsp->mnt_ns);
     115             : out_ns:
     116           0 :         kmem_cache_free(nsproxy_cachep, new_nsp);
     117           0 :         return ERR_PTR(err);
     118             : }
     119             : 
     120             : /*
     121             :  * called from clone.  This now handles copy for nsproxy and all
     122             :  * namespaces therein.
     123             :  */
     124        2993 : int copy_namespaces(unsigned long flags, struct task_struct *tsk)
     125             : {
     126        2993 :         struct nsproxy *old_ns = tsk->nsproxy;
     127        2993 :         struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
     128             :         struct nsproxy *new_ns;
     129             : 
     130        2993 :         if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
     131             :                               CLONE_NEWPID | CLONE_NEWNET)))) {
     132             :                 get_nsproxy(old_ns);
     133        2993 :                 return 0;
     134             :         }
     135             : 
     136           0 :         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           0 :         if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
     147             :                 (CLONE_NEWIPC | CLONE_SYSVSEM)) 
     148             :                 return -EINVAL;
     149             : 
     150           0 :         new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
     151           0 :         if (IS_ERR(new_ns))
     152           0 :                 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           0 :         if (ns->mnt_ns)
     161           0 :                 put_mnt_ns(ns->mnt_ns);
     162           0 :         if (ns->uts_ns)
     163             :                 put_uts_ns(ns->uts_ns);
     164           0 :         if (ns->ipc_ns)
     165           0 :                 put_ipc_ns(ns->ipc_ns);
     166           0 :         if (ns->pid_ns_for_children)
     167           0 :                 put_pid_ns(ns->pid_ns_for_children);
     168           0 :         put_net(ns->net_ns);
     169           0 :         kmem_cache_free(nsproxy_cachep, ns);
     170           0 : }
     171             : 
     172             : /*
     173             :  * Called from unshare. Unshare all the namespaces part of nsproxy.
     174             :  * On success, returns the new nsproxy.
     175             :  */
     176           1 : 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           1 :         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             :                                          new_fs ? new_fs : current->fs);
     192           1 :         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        2916 : void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
     202             : {
     203             :         struct nsproxy *ns;
     204             : 
     205             :         might_sleep();
     206             : 
     207             :         task_lock(p);
     208        2916 :         ns = p->nsproxy;
     209        2916 :         p->nsproxy = new;
     210             :         task_unlock(p);
     211             : 
     212        5832 :         if (ns && atomic_dec_and_test(&ns->count))
     213           0 :                 free_nsproxy(ns);
     214        2916 : }
     215             : 
     216        2915 : void exit_task_namespaces(struct task_struct *p)
     217             : {
     218        2915 :         switch_task_namespaces(p, NULL);
     219        2915 : }
     220             : 
     221           0 : SYSCALL_DEFINE2(setns, int, fd, int, nstype)
     222             : {
     223           0 :         struct task_struct *tsk = current;
     224             :         struct nsproxy *new_nsproxy;
     225           0 :         struct file *file;
     226             :         struct ns_common *ns;
     227             :         int err;
     228             : 
     229           0 :         file = proc_ns_fget(fd);
     230           0 :         if (IS_ERR(file))
     231             :                 return PTR_ERR(file);
     232             : 
     233             :         err = -EINVAL;
     234           0 :         ns = get_proc_ns(file_inode(file));
     235           0 :         if (nstype && (ns->ops->type != nstype))
     236             :                 goto out;
     237             : 
     238           0 :         new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
     239           0 :         if (IS_ERR(new_nsproxy)) {
     240             :                 err = PTR_ERR(new_nsproxy);
     241             :                 goto out;
     242             :         }
     243             : 
     244           0 :         err = ns->ops->install(new_nsproxy, ns);
     245           0 :         if (err) {
     246           0 :                 free_nsproxy(new_nsproxy);
     247             :                 goto out;
     248             :         }
     249           0 :         switch_task_namespaces(tsk, new_nsproxy);
     250             : out:
     251           0 :         fput(file);
     252             :         return err;
     253             : }
     254             : 
     255           1 : int __init nsproxy_cache_init(void)
     256             : {
     257           1 :         nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
     258           1 :         return 0;
     259             : }

Generated by: LCOV version 1.11