root/ipc/namespace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. inc_ipc_namespaces
  2. dec_ipc_namespaces
  3. create_ipc_ns
  4. copy_ipcs
  5. free_ipcs
  6. free_ipc_ns
  7. put_ipc_ns
  8. to_ipc_ns
  9. ipcns_get
  10. ipcns_put
  11. ipcns_install
  12. ipcns_owner

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * linux/ipc/namespace.c
   4  * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc.
   5  */
   6 
   7 #include <linux/ipc.h>
   8 #include <linux/msg.h>
   9 #include <linux/ipc_namespace.h>
  10 #include <linux/rcupdate.h>
  11 #include <linux/nsproxy.h>
  12 #include <linux/slab.h>
  13 #include <linux/cred.h>
  14 #include <linux/fs.h>
  15 #include <linux/mount.h>
  16 #include <linux/user_namespace.h>
  17 #include <linux/proc_ns.h>
  18 #include <linux/sched/task.h>
  19 
  20 #include "util.h"
  21 
  22 static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
  23 {
  24         return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES);
  25 }
  26 
  27 static void dec_ipc_namespaces(struct ucounts *ucounts)
  28 {
  29         dec_ucount(ucounts, UCOUNT_IPC_NAMESPACES);
  30 }
  31 
  32 static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
  33                                            struct ipc_namespace *old_ns)
  34 {
  35         struct ipc_namespace *ns;
  36         struct ucounts *ucounts;
  37         int err;
  38 
  39         err = -ENOSPC;
  40         ucounts = inc_ipc_namespaces(user_ns);
  41         if (!ucounts)
  42                 goto fail;
  43 
  44         err = -ENOMEM;
  45         ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
  46         if (ns == NULL)
  47                 goto fail_dec;
  48 
  49         err = ns_alloc_inum(&ns->ns);
  50         if (err)
  51                 goto fail_free;
  52         ns->ns.ops = &ipcns_operations;
  53 
  54         refcount_set(&ns->count, 1);
  55         ns->user_ns = get_user_ns(user_ns);
  56         ns->ucounts = ucounts;
  57 
  58         err = mq_init_ns(ns);
  59         if (err)
  60                 goto fail_put;
  61 
  62         sem_init_ns(ns);
  63         msg_init_ns(ns);
  64         shm_init_ns(ns);
  65 
  66         return ns;
  67 
  68 fail_put:
  69         put_user_ns(ns->user_ns);
  70         ns_free_inum(&ns->ns);
  71 fail_free:
  72         kfree(ns);
  73 fail_dec:
  74         dec_ipc_namespaces(ucounts);
  75 fail:
  76         return ERR_PTR(err);
  77 }
  78 
  79 struct ipc_namespace *copy_ipcs(unsigned long flags,
  80         struct user_namespace *user_ns, struct ipc_namespace *ns)
  81 {
  82         if (!(flags & CLONE_NEWIPC))
  83                 return get_ipc_ns(ns);
  84         return create_ipc_ns(user_ns, ns);
  85 }
  86 
  87 /*
  88  * free_ipcs - free all ipcs of one type
  89  * @ns:   the namespace to remove the ipcs from
  90  * @ids:  the table of ipcs to free
  91  * @free: the function called to free each individual ipc
  92  *
  93  * Called for each kind of ipc when an ipc_namespace exits.
  94  */
  95 void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
  96                void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
  97 {
  98         struct kern_ipc_perm *perm;
  99         int next_id;
 100         int total, in_use;
 101 
 102         down_write(&ids->rwsem);
 103 
 104         in_use = ids->in_use;
 105 
 106         for (total = 0, next_id = 0; total < in_use; next_id++) {
 107                 perm = idr_find(&ids->ipcs_idr, next_id);
 108                 if (perm == NULL)
 109                         continue;
 110                 rcu_read_lock();
 111                 ipc_lock_object(perm);
 112                 free(ns, perm);
 113                 total++;
 114         }
 115         up_write(&ids->rwsem);
 116 }
 117 
 118 static void free_ipc_ns(struct ipc_namespace *ns)
 119 {
 120         sem_exit_ns(ns);
 121         msg_exit_ns(ns);
 122         shm_exit_ns(ns);
 123 
 124         dec_ipc_namespaces(ns->ucounts);
 125         put_user_ns(ns->user_ns);
 126         ns_free_inum(&ns->ns);
 127         kfree(ns);
 128 }
 129 
 130 /*
 131  * put_ipc_ns - drop a reference to an ipc namespace.
 132  * @ns: the namespace to put
 133  *
 134  * If this is the last task in the namespace exiting, and
 135  * it is dropping the refcount to 0, then it can race with
 136  * a task in another ipc namespace but in a mounts namespace
 137  * which has this ipcns's mqueuefs mounted, doing some action
 138  * with one of the mqueuefs files.  That can raise the refcount.
 139  * So dropping the refcount, and raising the refcount when
 140  * accessing it through the VFS, are protected with mq_lock.
 141  *
 142  * (Clearly, a task raising the refcount on its own ipc_ns
 143  * needn't take mq_lock since it can't race with the last task
 144  * in the ipcns exiting).
 145  */
 146 void put_ipc_ns(struct ipc_namespace *ns)
 147 {
 148         if (refcount_dec_and_lock(&ns->count, &mq_lock)) {
 149                 mq_clear_sbinfo(ns);
 150                 spin_unlock(&mq_lock);
 151                 mq_put_mnt(ns);
 152                 free_ipc_ns(ns);
 153         }
 154 }
 155 
 156 static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns)
 157 {
 158         return container_of(ns, struct ipc_namespace, ns);
 159 }
 160 
 161 static struct ns_common *ipcns_get(struct task_struct *task)
 162 {
 163         struct ipc_namespace *ns = NULL;
 164         struct nsproxy *nsproxy;
 165 
 166         task_lock(task);
 167         nsproxy = task->nsproxy;
 168         if (nsproxy)
 169                 ns = get_ipc_ns(nsproxy->ipc_ns);
 170         task_unlock(task);
 171 
 172         return ns ? &ns->ns : NULL;
 173 }
 174 
 175 static void ipcns_put(struct ns_common *ns)
 176 {
 177         return put_ipc_ns(to_ipc_ns(ns));
 178 }
 179 
 180 static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new)
 181 {
 182         struct ipc_namespace *ns = to_ipc_ns(new);
 183         if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
 184             !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
 185                 return -EPERM;
 186 
 187         /* Ditch state from the old ipc namespace */
 188         exit_sem(current);
 189         put_ipc_ns(nsproxy->ipc_ns);
 190         nsproxy->ipc_ns = get_ipc_ns(ns);
 191         return 0;
 192 }
 193 
 194 static struct user_namespace *ipcns_owner(struct ns_common *ns)
 195 {
 196         return to_ipc_ns(ns)->user_ns;
 197 }
 198 
 199 const struct proc_ns_operations ipcns_operations = {
 200         .name           = "ipc",
 201         .type           = CLONE_NEWIPC,
 202         .get            = ipcns_get,
 203         .put            = ipcns_put,
 204         .install        = ipcns_install,
 205         .owner          = ipcns_owner,
 206 };

/* [<][>][^][v][top][bottom][index][help] */