~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/ipc/namespace.c

Version: ~ [ linux-5.16 ] ~ [ linux-5.15.13 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.90 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.170 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.224 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.261 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.296 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.298 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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_ACCOUNT);
 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->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         /* mq_put_mnt() waits for a grace period as kern_unmount()
121          * uses synchronize_rcu().
122          */
123         mq_put_mnt(ns);
124         sem_exit_ns(ns);
125         msg_exit_ns(ns);
126         shm_exit_ns(ns);
127 
128         dec_ipc_namespaces(ns->ucounts);
129         put_user_ns(ns->user_ns);
130         ns_free_inum(&ns->ns);
131         kfree(ns);
132 }
133 
134 static LLIST_HEAD(free_ipc_list);
135 static void free_ipc(struct work_struct *unused)
136 {
137         struct llist_node *node = llist_del_all(&free_ipc_list);
138         struct ipc_namespace *n, *t;
139 
140         llist_for_each_entry_safe(n, t, node, mnt_llist)
141                 free_ipc_ns(n);
142 }
143 
144 /*
145  * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount.
146  */
147 static DECLARE_WORK(free_ipc_work, free_ipc);
148 
149 /*
150  * put_ipc_ns - drop a reference to an ipc namespace.
151  * @ns: the namespace to put
152  *
153  * If this is the last task in the namespace exiting, and
154  * it is dropping the refcount to 0, then it can race with
155  * a task in another ipc namespace but in a mounts namespace
156  * which has this ipcns's mqueuefs mounted, doing some action
157  * with one of the mqueuefs files.  That can raise the refcount.
158  * So dropping the refcount, and raising the refcount when
159  * accessing it through the VFS, are protected with mq_lock.
160  *
161  * (Clearly, a task raising the refcount on its own ipc_ns
162  * needn't take mq_lock since it can't race with the last task
163  * in the ipcns exiting).
164  */
165 void put_ipc_ns(struct ipc_namespace *ns)
166 {
167         if (refcount_dec_and_lock(&ns->ns.count, &mq_lock)) {
168                 mq_clear_sbinfo(ns);
169                 spin_unlock(&mq_lock);
170 
171                 if (llist_add(&ns->mnt_llist, &free_ipc_list))
172                         schedule_work(&free_ipc_work);
173         }
174 }
175 
176 static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns)
177 {
178         return container_of(ns, struct ipc_namespace, ns);
179 }
180 
181 static struct ns_common *ipcns_get(struct task_struct *task)
182 {
183         struct ipc_namespace *ns = NULL;
184         struct nsproxy *nsproxy;
185 
186         task_lock(task);
187         nsproxy = task->nsproxy;
188         if (nsproxy)
189                 ns = get_ipc_ns(nsproxy->ipc_ns);
190         task_unlock(task);
191 
192         return ns ? &ns->ns : NULL;
193 }
194 
195 static void ipcns_put(struct ns_common *ns)
196 {
197         return put_ipc_ns(to_ipc_ns(ns));
198 }
199 
200 static int ipcns_install(struct nsset *nsset, struct ns_common *new)
201 {
202         struct nsproxy *nsproxy = nsset->nsproxy;
203         struct ipc_namespace *ns = to_ipc_ns(new);
204         if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
205             !ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN))
206                 return -EPERM;
207 
208         put_ipc_ns(nsproxy->ipc_ns);
209         nsproxy->ipc_ns = get_ipc_ns(ns);
210         return 0;
211 }
212 
213 static struct user_namespace *ipcns_owner(struct ns_common *ns)
214 {
215         return to_ipc_ns(ns)->user_ns;
216 }
217 
218 const struct proc_ns_operations ipcns_operations = {
219         .name           = "ipc",
220         .type           = CLONE_NEWIPC,
221         .get            = ipcns_get,
222         .put            = ipcns_put,
223         .install        = ipcns_install,
224         .owner          = ipcns_owner,
225 };
226 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp