Back to home page

LXR

 
 

    


0001 /*
0002  *  Copyright (C) 2006 IBM Corporation
0003  *
0004  *  Author: Serge Hallyn <serue@us.ibm.com>
0005  *
0006  *  This program is free software; you can redistribute it and/or
0007  *  modify it under the terms of the GNU General Public License as
0008  *  published by the Free Software Foundation, version 2 of the
0009  *  License.
0010  *
0011  *  Jun 2006 - namespaces support
0012  *             OpenVZ, SWsoft Inc.
0013  *             Pavel Emelianov <xemul@openvz.org>
0014  */
0015 
0016 #include <linux/slab.h>
0017 #include <linux/export.h>
0018 #include <linux/nsproxy.h>
0019 #include <linux/init_task.h>
0020 #include <linux/mnt_namespace.h>
0021 #include <linux/utsname.h>
0022 #include <linux/pid_namespace.h>
0023 #include <net/net_namespace.h>
0024 #include <linux/ipc_namespace.h>
0025 #include <linux/proc_ns.h>
0026 #include <linux/file.h>
0027 #include <linux/syscalls.h>
0028 #include <linux/cgroup.h>
0029 
0030 static struct kmem_cache *nsproxy_cachep;
0031 
0032 struct nsproxy init_nsproxy = {
0033     .count          = ATOMIC_INIT(1),
0034     .uts_ns         = &init_uts_ns,
0035 #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
0036     .ipc_ns         = &init_ipc_ns,
0037 #endif
0038     .mnt_ns         = NULL,
0039     .pid_ns_for_children    = &init_pid_ns,
0040 #ifdef CONFIG_NET
0041     .net_ns         = &init_net,
0042 #endif
0043 #ifdef CONFIG_CGROUPS
0044     .cgroup_ns      = &init_cgroup_ns,
0045 #endif
0046 };
0047 
0048 static inline struct nsproxy *create_nsproxy(void)
0049 {
0050     struct nsproxy *nsproxy;
0051 
0052     nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
0053     if (nsproxy)
0054         atomic_set(&nsproxy->count, 1);
0055     return nsproxy;
0056 }
0057 
0058 /*
0059  * Create new nsproxy and all of its the associated namespaces.
0060  * Return the newly created nsproxy.  Do not attach this to the task,
0061  * leave it to the caller to do proper locking and attach it to task.
0062  */
0063 static struct nsproxy *create_new_namespaces(unsigned long flags,
0064     struct task_struct *tsk, struct user_namespace *user_ns,
0065     struct fs_struct *new_fs)
0066 {
0067     struct nsproxy *new_nsp;
0068     int err;
0069 
0070     new_nsp = create_nsproxy();
0071     if (!new_nsp)
0072         return ERR_PTR(-ENOMEM);
0073 
0074     new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
0075     if (IS_ERR(new_nsp->mnt_ns)) {
0076         err = PTR_ERR(new_nsp->mnt_ns);
0077         goto out_ns;
0078     }
0079 
0080     new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
0081     if (IS_ERR(new_nsp->uts_ns)) {
0082         err = PTR_ERR(new_nsp->uts_ns);
0083         goto out_uts;
0084     }
0085 
0086     new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
0087     if (IS_ERR(new_nsp->ipc_ns)) {
0088         err = PTR_ERR(new_nsp->ipc_ns);
0089         goto out_ipc;
0090     }
0091 
0092     new_nsp->pid_ns_for_children =
0093         copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
0094     if (IS_ERR(new_nsp->pid_ns_for_children)) {
0095         err = PTR_ERR(new_nsp->pid_ns_for_children);
0096         goto out_pid;
0097     }
0098 
0099     new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns,
0100                         tsk->nsproxy->cgroup_ns);
0101     if (IS_ERR(new_nsp->cgroup_ns)) {
0102         err = PTR_ERR(new_nsp->cgroup_ns);
0103         goto out_cgroup;
0104     }
0105 
0106     new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
0107     if (IS_ERR(new_nsp->net_ns)) {
0108         err = PTR_ERR(new_nsp->net_ns);
0109         goto out_net;
0110     }
0111 
0112     return new_nsp;
0113 
0114 out_net:
0115     put_cgroup_ns(new_nsp->cgroup_ns);
0116 out_cgroup:
0117     if (new_nsp->pid_ns_for_children)
0118         put_pid_ns(new_nsp->pid_ns_for_children);
0119 out_pid:
0120     if (new_nsp->ipc_ns)
0121         put_ipc_ns(new_nsp->ipc_ns);
0122 out_ipc:
0123     if (new_nsp->uts_ns)
0124         put_uts_ns(new_nsp->uts_ns);
0125 out_uts:
0126     if (new_nsp->mnt_ns)
0127         put_mnt_ns(new_nsp->mnt_ns);
0128 out_ns:
0129     kmem_cache_free(nsproxy_cachep, new_nsp);
0130     return ERR_PTR(err);
0131 }
0132 
0133 /*
0134  * called from clone.  This now handles copy for nsproxy and all
0135  * namespaces therein.
0136  */
0137 int copy_namespaces(unsigned long flags, struct task_struct *tsk)
0138 {
0139     struct nsproxy *old_ns = tsk->nsproxy;
0140     struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
0141     struct nsproxy *new_ns;
0142 
0143     if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
0144                   CLONE_NEWPID | CLONE_NEWNET |
0145                   CLONE_NEWCGROUP)))) {
0146         get_nsproxy(old_ns);
0147         return 0;
0148     }
0149 
0150     if (!ns_capable(user_ns, CAP_SYS_ADMIN))
0151         return -EPERM;
0152 
0153     /*
0154      * CLONE_NEWIPC must detach from the undolist: after switching
0155      * to a new ipc namespace, the semaphore arrays from the old
0156      * namespace are unreachable.  In clone parlance, CLONE_SYSVSEM
0157      * means share undolist with parent, so we must forbid using
0158      * it along with CLONE_NEWIPC.
0159      */
0160     if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
0161         (CLONE_NEWIPC | CLONE_SYSVSEM)) 
0162         return -EINVAL;
0163 
0164     new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
0165     if (IS_ERR(new_ns))
0166         return  PTR_ERR(new_ns);
0167 
0168     tsk->nsproxy = new_ns;
0169     return 0;
0170 }
0171 
0172 void free_nsproxy(struct nsproxy *ns)
0173 {
0174     if (ns->mnt_ns)
0175         put_mnt_ns(ns->mnt_ns);
0176     if (ns->uts_ns)
0177         put_uts_ns(ns->uts_ns);
0178     if (ns->ipc_ns)
0179         put_ipc_ns(ns->ipc_ns);
0180     if (ns->pid_ns_for_children)
0181         put_pid_ns(ns->pid_ns_for_children);
0182     put_cgroup_ns(ns->cgroup_ns);
0183     put_net(ns->net_ns);
0184     kmem_cache_free(nsproxy_cachep, ns);
0185 }
0186 
0187 /*
0188  * Called from unshare. Unshare all the namespaces part of nsproxy.
0189  * On success, returns the new nsproxy.
0190  */
0191 int unshare_nsproxy_namespaces(unsigned long unshare_flags,
0192     struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)
0193 {
0194     struct user_namespace *user_ns;
0195     int err = 0;
0196 
0197     if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
0198                    CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP)))
0199         return 0;
0200 
0201     user_ns = new_cred ? new_cred->user_ns : current_user_ns();
0202     if (!ns_capable(user_ns, CAP_SYS_ADMIN))
0203         return -EPERM;
0204 
0205     *new_nsp = create_new_namespaces(unshare_flags, current, user_ns,
0206                      new_fs ? new_fs : current->fs);
0207     if (IS_ERR(*new_nsp)) {
0208         err = PTR_ERR(*new_nsp);
0209         goto out;
0210     }
0211 
0212 out:
0213     return err;
0214 }
0215 
0216 void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)
0217 {
0218     struct nsproxy *ns;
0219 
0220     might_sleep();
0221 
0222     task_lock(p);
0223     ns = p->nsproxy;
0224     p->nsproxy = new;
0225     task_unlock(p);
0226 
0227     if (ns && atomic_dec_and_test(&ns->count))
0228         free_nsproxy(ns);
0229 }
0230 
0231 void exit_task_namespaces(struct task_struct *p)
0232 {
0233     switch_task_namespaces(p, NULL);
0234 }
0235 
0236 SYSCALL_DEFINE2(setns, int, fd, int, nstype)
0237 {
0238     struct task_struct *tsk = current;
0239     struct nsproxy *new_nsproxy;
0240     struct file *file;
0241     struct ns_common *ns;
0242     int err;
0243 
0244     file = proc_ns_fget(fd);
0245     if (IS_ERR(file))
0246         return PTR_ERR(file);
0247 
0248     err = -EINVAL;
0249     ns = get_proc_ns(file_inode(file));
0250     if (nstype && (ns->ops->type != nstype))
0251         goto out;
0252 
0253     new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
0254     if (IS_ERR(new_nsproxy)) {
0255         err = PTR_ERR(new_nsproxy);
0256         goto out;
0257     }
0258 
0259     err = ns->ops->install(new_nsproxy, ns);
0260     if (err) {
0261         free_nsproxy(new_nsproxy);
0262         goto out;
0263     }
0264     switch_task_namespaces(tsk, new_nsproxy);
0265 out:
0266     fput(file);
0267     return err;
0268 }
0269 
0270 int __init nsproxy_cache_init(void)
0271 {
0272     nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
0273     return 0;
0274 }