Back to home page

LXR

 
 

    


0001 /*
0002  * linux/ipc/namespace.c
0003  * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc.
0004  */
0005 
0006 #include <linux/ipc.h>
0007 #include <linux/msg.h>
0008 #include <linux/ipc_namespace.h>
0009 #include <linux/rcupdate.h>
0010 #include <linux/nsproxy.h>
0011 #include <linux/slab.h>
0012 #include <linux/fs.h>
0013 #include <linux/mount.h>
0014 #include <linux/user_namespace.h>
0015 #include <linux/proc_ns.h>
0016 
0017 #include "util.h"
0018 
0019 static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
0020 {
0021     return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES);
0022 }
0023 
0024 static void dec_ipc_namespaces(struct ucounts *ucounts)
0025 {
0026     dec_ucount(ucounts, UCOUNT_IPC_NAMESPACES);
0027 }
0028 
0029 static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
0030                        struct ipc_namespace *old_ns)
0031 {
0032     struct ipc_namespace *ns;
0033     struct ucounts *ucounts;
0034     int err;
0035 
0036     err = -ENOSPC;
0037     ucounts = inc_ipc_namespaces(user_ns);
0038     if (!ucounts)
0039         goto fail;
0040 
0041     err = -ENOMEM;
0042     ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
0043     if (ns == NULL)
0044         goto fail_dec;
0045 
0046     err = ns_alloc_inum(&ns->ns);
0047     if (err)
0048         goto fail_free;
0049     ns->ns.ops = &ipcns_operations;
0050 
0051     atomic_set(&ns->count, 1);
0052     ns->user_ns = get_user_ns(user_ns);
0053     ns->ucounts = ucounts;
0054 
0055     err = mq_init_ns(ns);
0056     if (err)
0057         goto fail_put;
0058 
0059     sem_init_ns(ns);
0060     msg_init_ns(ns);
0061     shm_init_ns(ns);
0062 
0063     return ns;
0064 
0065 fail_put:
0066     put_user_ns(ns->user_ns);
0067     ns_free_inum(&ns->ns);
0068 fail_free:
0069     kfree(ns);
0070 fail_dec:
0071     dec_ipc_namespaces(ucounts);
0072 fail:
0073     return ERR_PTR(err);
0074 }
0075 
0076 struct ipc_namespace *copy_ipcs(unsigned long flags,
0077     struct user_namespace *user_ns, struct ipc_namespace *ns)
0078 {
0079     if (!(flags & CLONE_NEWIPC))
0080         return get_ipc_ns(ns);
0081     return create_ipc_ns(user_ns, ns);
0082 }
0083 
0084 /*
0085  * free_ipcs - free all ipcs of one type
0086  * @ns:   the namespace to remove the ipcs from
0087  * @ids:  the table of ipcs to free
0088  * @free: the function called to free each individual ipc
0089  *
0090  * Called for each kind of ipc when an ipc_namespace exits.
0091  */
0092 void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
0093            void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
0094 {
0095     struct kern_ipc_perm *perm;
0096     int next_id;
0097     int total, in_use;
0098 
0099     down_write(&ids->rwsem);
0100 
0101     in_use = ids->in_use;
0102 
0103     for (total = 0, next_id = 0; total < in_use; next_id++) {
0104         perm = idr_find(&ids->ipcs_idr, next_id);
0105         if (perm == NULL)
0106             continue;
0107         rcu_read_lock();
0108         ipc_lock_object(perm);
0109         free(ns, perm);
0110         total++;
0111     }
0112     up_write(&ids->rwsem);
0113 }
0114 
0115 static void free_ipc_ns(struct ipc_namespace *ns)
0116 {
0117     sem_exit_ns(ns);
0118     msg_exit_ns(ns);
0119     shm_exit_ns(ns);
0120 
0121     dec_ipc_namespaces(ns->ucounts);
0122     put_user_ns(ns->user_ns);
0123     ns_free_inum(&ns->ns);
0124     kfree(ns);
0125 }
0126 
0127 /*
0128  * put_ipc_ns - drop a reference to an ipc namespace.
0129  * @ns: the namespace to put
0130  *
0131  * If this is the last task in the namespace exiting, and
0132  * it is dropping the refcount to 0, then it can race with
0133  * a task in another ipc namespace but in a mounts namespace
0134  * which has this ipcns's mqueuefs mounted, doing some action
0135  * with one of the mqueuefs files.  That can raise the refcount.
0136  * So dropping the refcount, and raising the refcount when
0137  * accessing it through the VFS, are protected with mq_lock.
0138  *
0139  * (Clearly, a task raising the refcount on its own ipc_ns
0140  * needn't take mq_lock since it can't race with the last task
0141  * in the ipcns exiting).
0142  */
0143 void put_ipc_ns(struct ipc_namespace *ns)
0144 {
0145     if (atomic_dec_and_lock(&ns->count, &mq_lock)) {
0146         mq_clear_sbinfo(ns);
0147         spin_unlock(&mq_lock);
0148         mq_put_mnt(ns);
0149         free_ipc_ns(ns);
0150     }
0151 }
0152 
0153 static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns)
0154 {
0155     return container_of(ns, struct ipc_namespace, ns);
0156 }
0157 
0158 static struct ns_common *ipcns_get(struct task_struct *task)
0159 {
0160     struct ipc_namespace *ns = NULL;
0161     struct nsproxy *nsproxy;
0162 
0163     task_lock(task);
0164     nsproxy = task->nsproxy;
0165     if (nsproxy)
0166         ns = get_ipc_ns(nsproxy->ipc_ns);
0167     task_unlock(task);
0168 
0169     return ns ? &ns->ns : NULL;
0170 }
0171 
0172 static void ipcns_put(struct ns_common *ns)
0173 {
0174     return put_ipc_ns(to_ipc_ns(ns));
0175 }
0176 
0177 static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new)
0178 {
0179     struct ipc_namespace *ns = to_ipc_ns(new);
0180     if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
0181         !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
0182         return -EPERM;
0183 
0184     /* Ditch state from the old ipc namespace */
0185     exit_sem(current);
0186     put_ipc_ns(nsproxy->ipc_ns);
0187     nsproxy->ipc_ns = get_ipc_ns(ns);
0188     return 0;
0189 }
0190 
0191 static struct user_namespace *ipcns_owner(struct ns_common *ns)
0192 {
0193     return to_ipc_ns(ns)->user_ns;
0194 }
0195 
0196 const struct proc_ns_operations ipcns_operations = {
0197     .name       = "ipc",
0198     .type       = CLONE_NEWIPC,
0199     .get        = ipcns_get,
0200     .put        = ipcns_put,
0201     .install    = ipcns_install,
0202     .owner      = ipcns_owner,
0203 };