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/ipc/namespace.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  * linux/ipc/namespace.c
    3  * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc.
    4  */
    5 
    6 #include <linux/ipc.h>
    7 #include <linux/msg.h>
    8 #include <linux/ipc_namespace.h>
    9 #include <linux/rcupdate.h>
   10 #include <linux/nsproxy.h>
   11 #include <linux/slab.h>
   12 #include <linux/fs.h>
   13 #include <linux/mount.h>
   14 #include <linux/user_namespace.h>
   15 #include <linux/proc_fs.h>
   16 
   17 #include "util.h"
   18 
   19 static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
   20                                            struct ipc_namespace *old_ns)
   21 {
   22         struct ipc_namespace *ns;
   23         int err;
   24 
   25         ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
   26         if (ns == NULL)
   27                 return ERR_PTR(-ENOMEM);
   28 
   29         err = proc_alloc_inum(&ns->proc_inum);
   30         if (err) {
   31                 kfree(ns);
   32                 return ERR_PTR(err);
   33         }
   34 
   35         atomic_set(&ns->count, 1);
   36         err = mq_init_ns(ns);
   37         if (err) {
   38                 proc_free_inum(ns->proc_inum);
   39                 kfree(ns);
   40                 return ERR_PTR(err);
   41         }
   42         atomic_inc(&nr_ipc_ns);
   43 
   44         sem_init_ns(ns);
   45         msg_init_ns(ns);
   46         shm_init_ns(ns);
   47 
   48         /*
   49          * msgmni has already been computed for the new ipc ns.
   50          * Thus, do the ipcns creation notification before registering that
   51          * new ipcns in the chain.
   52          */
   53         ipcns_notify(IPCNS_CREATED);
   54         register_ipcns_notifier(ns);
   55 
   56         ns->user_ns = get_user_ns(user_ns);
   57 
   58         return ns;
   59 }
   60 
   61 struct ipc_namespace *copy_ipcs(unsigned long flags,
   62         struct user_namespace *user_ns, struct ipc_namespace *ns)
   63 {
   64         if (!(flags & CLONE_NEWIPC))
   65                 return get_ipc_ns(ns);
   66         return create_ipc_ns(user_ns, ns);
   67 }
   68 
   69 /*
   70  * free_ipcs - free all ipcs of one type
   71  * @ns:   the namespace to remove the ipcs from
   72  * @ids:  the table of ipcs to free
   73  * @free: the function called to free each individual ipc
   74  *
   75  * Called for each kind of ipc when an ipc_namespace exits.
   76  */
   77 void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
   78                void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
   79 {
   80         struct kern_ipc_perm *perm;
   81         int next_id;
   82         int total, in_use;
   83 
   84         down_write(&ids->rw_mutex);
   85 
   86         in_use = ids->in_use;
   87 
   88         for (total = 0, next_id = 0; total < in_use; next_id++) {
   89                 perm = idr_find(&ids->ipcs_idr, next_id);
   90                 if (perm == NULL)
   91                         continue;
   92                 ipc_lock_by_ptr(perm);
   93                 free(ns, perm);
   94                 total++;
   95         }
   96         up_write(&ids->rw_mutex);
   97 }
   98 
   99 static void free_ipc_ns(struct ipc_namespace *ns)
  100 {
  101         /*
  102          * Unregistering the hotplug notifier at the beginning guarantees
  103          * that the ipc namespace won't be freed while we are inside the
  104          * callback routine. Since the blocking_notifier_chain_XXX routines
  105          * hold a rw lock on the notifier list, unregister_ipcns_notifier()
  106          * won't take the rw lock before blocking_notifier_call_chain() has
  107          * released the rd lock.
  108          */
  109         unregister_ipcns_notifier(ns);
  110         sem_exit_ns(ns);
  111         msg_exit_ns(ns);
  112         shm_exit_ns(ns);
  113         atomic_dec(&nr_ipc_ns);
  114 
  115         /*
  116          * Do the ipcns removal notification after decrementing nr_ipc_ns in
  117          * order to have a correct value when recomputing msgmni.
  118          */
  119         ipcns_notify(IPCNS_REMOVED);
  120         put_user_ns(ns->user_ns);
  121         proc_free_inum(ns->proc_inum);
  122         kfree(ns);
  123 }
  124 
  125 /*
  126  * put_ipc_ns - drop a reference to an ipc namespace.
  127  * @ns: the namespace to put
  128  *
  129  * If this is the last task in the namespace exiting, and
  130  * it is dropping the refcount to 0, then it can race with
  131  * a task in another ipc namespace but in a mounts namespace
  132  * which has this ipcns's mqueuefs mounted, doing some action
  133  * with one of the mqueuefs files.  That can raise the refcount.
  134  * So dropping the refcount, and raising the refcount when
  135  * accessing it through the VFS, are protected with mq_lock.
  136  *
  137  * (Clearly, a task raising the refcount on its own ipc_ns
  138  * needn't take mq_lock since it can't race with the last task
  139  * in the ipcns exiting).
  140  */
  141 void put_ipc_ns(struct ipc_namespace *ns)
  142 {
  143         if (atomic_dec_and_lock(&ns->count, &mq_lock)) {
  144                 mq_clear_sbinfo(ns);
  145                 spin_unlock(&mq_lock);
  146                 mq_put_mnt(ns);
  147                 free_ipc_ns(ns);
  148         }
  149 }
  150 
  151 static void *ipcns_get(struct task_struct *task)
  152 {
  153         struct ipc_namespace *ns = NULL;
  154         struct nsproxy *nsproxy;
  155 
  156         rcu_read_lock();
  157         nsproxy = task_nsproxy(task);
  158         if (nsproxy)
  159                 ns = get_ipc_ns(nsproxy->ipc_ns);
  160         rcu_read_unlock();
  161 
  162         return ns;
  163 }
  164 
  165 static void ipcns_put(void *ns)
  166 {
  167         return put_ipc_ns(ns);
  168 }
  169 
  170 static int ipcns_install(struct nsproxy *nsproxy, void *new)
  171 {
  172         struct ipc_namespace *ns = new;
  173         if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
  174             !nsown_capable(CAP_SYS_ADMIN))
  175                 return -EPERM;
  176 
  177         /* Ditch state from the old ipc namespace */
  178         exit_sem(current);
  179         put_ipc_ns(nsproxy->ipc_ns);
  180         nsproxy->ipc_ns = get_ipc_ns(ns);
  181         return 0;
  182 }
  183 
  184 static unsigned int ipcns_inum(void *vp)
  185 {
  186         struct ipc_namespace *ns = vp;
  187 
  188         return ns->proc_inum;
  189 }
  190 
  191 const struct proc_ns_operations ipcns_operations = {
  192         .name           = "ipc",
  193         .type           = CLONE_NEWIPC,
  194         .get            = ipcns_get,
  195         .put            = ipcns_put,
  196         .install        = ipcns_install,
  197         .inum           = ipcns_inum,
  198 };

Cache object: ff7cad8f1c83de1e2ca35e2994de9a88


[ 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.