Branch data Line data Source code
1 : : /*
2 : : * linux/ipc/msg.c
3 : : * Copyright (C) 1992 Krishna Balasubramanian
4 : : *
5 : : * Removed all the remaining kerneld mess
6 : : * Catch the -EFAULT stuff properly
7 : : * Use GFP_KERNEL for messages as in 1.2
8 : : * Fixed up the unchecked user space derefs
9 : : * Copyright (C) 1998 Alan Cox & Andi Kleen
10 : : *
11 : : * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
12 : : *
13 : : * mostly rewritten, threaded and wake-one semantics added
14 : : * MSGMAX limit removed, sysctl's added
15 : : * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
16 : : *
17 : : * support for audit of ipc object properties and permission changes
18 : : * Dustin Kirkland <dustin.kirkland@us.ibm.com>
19 : : *
20 : : * namespaces support
21 : : * OpenVZ, SWsoft Inc.
22 : : * Pavel Emelianov <xemul@openvz.org>
23 : : */
24 : :
25 : : #include <linux/capability.h>
26 : : #include <linux/msg.h>
27 : : #include <linux/spinlock.h>
28 : : #include <linux/init.h>
29 : : #include <linux/mm.h>
30 : : #include <linux/proc_fs.h>
31 : : #include <linux/list.h>
32 : : #include <linux/security.h>
33 : : #include <linux/sched.h>
34 : : #include <linux/syscalls.h>
35 : : #include <linux/audit.h>
36 : : #include <linux/seq_file.h>
37 : : #include <linux/rwsem.h>
38 : : #include <linux/nsproxy.h>
39 : : #include <linux/ipc_namespace.h>
40 : :
41 : : #include <asm/current.h>
42 : : #include <asm/uaccess.h>
43 : : #include "util.h"
44 : :
45 : : /*
46 : : * one msg_receiver structure for each sleeping receiver:
47 : : */
48 : : struct msg_receiver {
49 : : struct list_head r_list;
50 : : struct task_struct *r_tsk;
51 : :
52 : : int r_mode;
53 : : long r_msgtype;
54 : : long r_maxsize;
55 : :
56 : : struct msg_msg *volatile r_msg;
57 : : };
58 : :
59 : : /* one msg_sender for each sleeping sender */
60 : : struct msg_sender {
61 : : struct list_head list;
62 : : struct task_struct *tsk;
63 : : };
64 : :
65 : : #define SEARCH_ANY 1
66 : : #define SEARCH_EQUAL 2
67 : : #define SEARCH_NOTEQUAL 3
68 : : #define SEARCH_LESSEQUAL 4
69 : : #define SEARCH_NUMBER 5
70 : :
71 : : #define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
72 : :
73 : : static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
74 : : static int newque(struct ipc_namespace *, struct ipc_params *);
75 : : #ifdef CONFIG_PROC_FS
76 : : static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
77 : : #endif
78 : :
79 : : /*
80 : : * Scale msgmni with the available lowmem size: the memory dedicated to msg
81 : : * queues should occupy at most 1/MSG_MEM_SCALE of lowmem.
82 : : * Also take into account the number of nsproxies created so far.
83 : : * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
84 : : */
85 : 0 : void recompute_msgmni(struct ipc_namespace *ns)
86 : : {
87 : : struct sysinfo i;
88 : : unsigned long allowed;
89 : : int nb_ns;
90 : :
91 : 0 : si_meminfo(&i);
92 : 0 : allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit)
93 : : / MSGMNB;
94 : 0 : nb_ns = atomic_read(&nr_ipc_ns);
95 : 0 : allowed /= nb_ns;
96 : :
97 [ # # ]: 0 : if (allowed < MSGMNI) {
98 : 0 : ns->msg_ctlmni = MSGMNI;
99 : 0 : return;
100 : : }
101 : :
102 [ # # ]: 0 : if (allowed > IPCMNI / nb_ns) {
103 : 0 : ns->msg_ctlmni = IPCMNI / nb_ns;
104 : 0 : return;
105 : : }
106 : :
107 : 0 : ns->msg_ctlmni = allowed;
108 : : }
109 : :
110 : 0 : void msg_init_ns(struct ipc_namespace *ns)
111 : : {
112 : 0 : ns->msg_ctlmax = MSGMAX;
113 : 0 : ns->msg_ctlmnb = MSGMNB;
114 : :
115 : 0 : recompute_msgmni(ns);
116 : :
117 : 0 : atomic_set(&ns->msg_bytes, 0);
118 : 0 : atomic_set(&ns->msg_hdrs, 0);
119 : 0 : ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
120 : 0 : }
121 : :
122 : : #ifdef CONFIG_IPC_NS
123 : : void msg_exit_ns(struct ipc_namespace *ns)
124 : : {
125 : : free_ipcs(ns, &msg_ids(ns), freeque);
126 : : idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
127 : : }
128 : : #endif
129 : :
130 : 0 : void __init msg_init(void)
131 : : {
132 : 0 : msg_init_ns(&init_ipc_ns);
133 : :
134 : 0 : printk(KERN_INFO "msgmni has been set to %d\n",
135 : : init_ipc_ns.msg_ctlmni);
136 : :
137 : 0 : ipc_init_proc_interface("sysvipc/msg",
138 : : " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
139 : : IPC_MSG_IDS, sysvipc_msg_proc_show);
140 : 0 : }
141 : :
142 : : static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id)
143 : : {
144 : 5 : struct kern_ipc_perm *ipcp = ipc_obtain_object(&msg_ids(ns), id);
145 : :
146 : : if (IS_ERR(ipcp))
147 : : return ERR_CAST(ipcp);
148 : :
149 : : return container_of(ipcp, struct msg_queue, q_perm);
150 : : }
151 : :
152 : : static inline struct msg_queue *msq_obtain_object_check(struct ipc_namespace *ns,
153 : : int id)
154 : : {
155 : 47098369 : struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&msg_ids(ns), id);
156 : :
157 : : if (IS_ERR(ipcp))
158 : : return ERR_CAST(ipcp);
159 : :
160 : : return container_of(ipcp, struct msg_queue, q_perm);
161 : : }
162 : :
163 : : static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
164 : : {
165 : 4441 : ipc_rmid(&msg_ids(ns), &s->q_perm);
166 : : }
167 : :
168 : 0 : static void msg_rcu_free(struct rcu_head *head)
169 : : {
170 : : struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
171 : 4440 : struct msg_queue *msq = ipc_rcu_to_struct(p);
172 : :
173 : 4440 : security_msg_queue_free(msq);
174 : 4441 : ipc_rcu_free(head);
175 : 4430 : }
176 : :
177 : : /**
178 : : * newque - Create a new msg queue
179 : : * @ns: namespace
180 : : * @params: ptr to the structure that contains the key and msgflg
181 : : *
182 : : * Called with msg_ids.rwsem held (writer)
183 : : */
184 : 0 : static int newque(struct ipc_namespace *ns, struct ipc_params *params)
185 : : {
186 : : struct msg_queue *msq;
187 : : int id, retval;
188 : 4442 : key_t key = params->key;
189 : 4442 : int msgflg = params->flg;
190 : :
191 : 4442 : msq = ipc_rcu_alloc(sizeof(*msq));
192 [ + - ]: 4442 : if (!msq)
193 : : return -ENOMEM;
194 : :
195 : 4442 : msq->q_perm.mode = msgflg & S_IRWXUGO;
196 : 4442 : msq->q_perm.key = key;
197 : :
198 : 4442 : msq->q_perm.security = NULL;
199 : 4442 : retval = security_msg_queue_alloc(msq);
200 [ - + ]: 4442 : if (retval) {
201 : 0 : ipc_rcu_putref(msq, ipc_rcu_free);
202 : 0 : return retval;
203 : : }
204 : :
205 : : /* ipc_addid() locks msq upon success. */
206 : 4442 : id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
207 [ + + ]: 4442 : if (id < 0) {
208 : 1 : ipc_rcu_putref(msq, msg_rcu_free);
209 : 1 : return id;
210 : : }
211 : :
212 : 4441 : msq->q_stime = msq->q_rtime = 0;
213 : 4441 : msq->q_ctime = get_seconds();
214 : 4441 : msq->q_cbytes = msq->q_qnum = 0;
215 : 4441 : msq->q_qbytes = ns->msg_ctlmnb;
216 : 4441 : msq->q_lspid = msq->q_lrpid = 0;
217 : 4441 : INIT_LIST_HEAD(&msq->q_messages);
218 : 4441 : INIT_LIST_HEAD(&msq->q_receivers);
219 : 4441 : INIT_LIST_HEAD(&msq->q_senders);
220 : :
221 : : ipc_unlock_object(&msq->q_perm);
222 : : rcu_read_unlock();
223 : :
224 : 4441 : return msq->q_perm.id;
225 : : }
226 : :
227 : : static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
228 : : {
229 : 2840828 : mss->tsk = current;
230 : 2840828 : current->state = TASK_INTERRUPTIBLE;
231 : 2840828 : list_add_tail(&mss->list, &msq->q_senders);
232 : : }
233 : :
234 : : static inline void ss_del(struct msg_sender *mss)
235 : : {
236 [ + ]: 2841549 : if (mss->list.next != NULL)
237 : : list_del(&mss->list);
238 : : }
239 : :
240 : 0 : static void ss_wakeup(struct list_head *h, int kill)
241 : : {
242 : : struct msg_sender *mss, *t;
243 : :
244 [ + + ]: 62822460 : list_for_each_entry_safe(mss, t, h, list) {
245 [ + + ]: 39387705 : if (kill)
246 : 1 : mss->list.next = NULL;
247 : 39387705 : wake_up_process(mss->tsk);
248 : : }
249 : 23434755 : }
250 : :
251 : 0 : static void expunge_all(struct msg_queue *msq, int res)
252 : : {
253 : : struct msg_receiver *msr, *t;
254 : :
255 [ + + ]: 4443 : list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
256 : 1 : msr->r_msg = NULL;
257 : 1 : wake_up_process(msr->r_tsk);
258 : 1 : smp_mb();
259 : 1 : msr->r_msg = ERR_PTR(res);
260 : : }
261 : 4442 : }
262 : :
263 : : /*
264 : : * freeque() wakes up waiters on the sender and receiver waiting queue,
265 : : * removes the message queue from message queue ID IDR, and cleans up all the
266 : : * messages associated with this queue.
267 : : *
268 : : * msg_ids.rwsem (writer) and the spinlock for this message queue are held
269 : : * before freeque() is called. msg_ids.rwsem remains locked on exit.
270 : : */
271 : 0 : static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
272 : : {
273 : : struct msg_msg *msg, *t;
274 : : struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
275 : :
276 : 4441 : expunge_all(msq, -EIDRM);
277 : 4441 : ss_wakeup(&msq->q_senders, 1);
278 : : msg_rmid(ns, msq);
279 : : ipc_unlock_object(&msq->q_perm);
280 : : rcu_read_unlock();
281 : :
282 [ + + ]: 17122 : list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
283 : 8240 : atomic_dec(&ns->msg_hdrs);
284 : 8240 : free_msg(msg);
285 : : }
286 : 4441 : atomic_sub(msq->q_cbytes, &ns->msg_bytes);
287 : 4441 : ipc_rcu_putref(msq, msg_rcu_free);
288 : 4441 : }
289 : :
290 : : /*
291 : : * Called with msg_ids.rwsem and ipcp locked.
292 : : */
293 : 0 : static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
294 : : {
295 : : struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
296 : :
297 : 17815 : return security_msg_queue_associate(msq, msgflg);
298 : : }
299 : :
300 : 0 : SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
301 : : {
302 : : struct ipc_namespace *ns;
303 : : struct ipc_ops msg_ops;
304 : : struct ipc_params msg_params;
305 : :
306 : 22264 : ns = current->nsproxy->ipc_ns;
307 : :
308 : 22264 : msg_ops.getnew = newque;
309 : 22264 : msg_ops.associate = msg_security;
310 : 22264 : msg_ops.more_checks = NULL;
311 : :
312 : 22264 : msg_params.key = key;
313 : 22264 : msg_params.flg = msgflg;
314 : :
315 : 22264 : return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
316 : : }
317 : :
318 : : static inline unsigned long
319 : : copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
320 : : {
321 [ + - - ]: 8 : switch(version) {
322 : : case IPC_64:
323 : : return copy_to_user(buf, in, sizeof(*in));
324 : : case IPC_OLD:
325 : : {
326 : : struct msqid_ds out;
327 : :
328 : 0 : memset(&out, 0, sizeof(out));
329 : :
330 : 0 : ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
331 : :
332 : 23 : out.msg_stime = in->msg_stime;
333 : 23 : out.msg_rtime = in->msg_rtime;
334 : 23 : out.msg_ctime = in->msg_ctime;
335 : :
336 [ + - ]: 23 : if (in->msg_cbytes > USHRT_MAX)
337 : 23 : out.msg_cbytes = USHRT_MAX;
338 : : else
339 : 0 : out.msg_cbytes = in->msg_cbytes;
340 : 0 : out.msg_lcbytes = in->msg_cbytes;
341 : :
342 [ # # ]: 0 : if (in->msg_qnum > USHRT_MAX)
343 : 0 : out.msg_qnum = USHRT_MAX;
344 : : else
345 : 0 : out.msg_qnum = in->msg_qnum;
346 : :
347 [ # # ]: 0 : if (in->msg_qbytes > USHRT_MAX)
348 : 0 : out.msg_qbytes = USHRT_MAX;
349 : : else
350 : 0 : out.msg_qbytes = in->msg_qbytes;
351 : 0 : out.msg_lqbytes = in->msg_qbytes;
352 : :
353 : 0 : out.msg_lspid = in->msg_lspid;
354 : 0 : out.msg_lrpid = in->msg_lrpid;
355 : :
356 : : return copy_to_user(buf, &out, sizeof(out));
357 : : }
358 : : default:
359 : : return -EINVAL;
360 : : }
361 : : }
362 : :
363 : : static inline unsigned long
364 : : copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
365 : : {
366 [ + - - ]: 2 : switch(version) {
367 : : case IPC_64:
368 [ + + ]: 2 : if (copy_from_user(out, buf, sizeof(*out)))
369 : : return -EFAULT;
370 : : return 0;
371 : : case IPC_OLD:
372 : : {
373 : : struct msqid_ds tbuf_old;
374 : :
375 [ # # ]: 4444 : if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
376 : : return -EFAULT;
377 : :
378 : 0 : out->msg_perm.uid = tbuf_old.msg_perm.uid;
379 : 0 : out->msg_perm.gid = tbuf_old.msg_perm.gid;
380 : 0 : out->msg_perm.mode = tbuf_old.msg_perm.mode;
381 : :
382 [ # # ]: 0 : if (tbuf_old.msg_qbytes == 0)
383 : 0 : out->msg_qbytes = tbuf_old.msg_lqbytes;
384 : : else
385 : 0 : out->msg_qbytes = tbuf_old.msg_qbytes;
386 : :
387 : : return 0;
388 : : }
389 : : default:
390 : : return -EINVAL;
391 : : }
392 : : }
393 : :
394 : : /*
395 : : * This function handles some msgctl commands which require the rwsem
396 : : * to be held in write mode.
397 : : * NOTE: no locks must be held, the rwsem is taken inside this function.
398 : : */
399 : 0 : static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
400 : : struct msqid_ds __user *buf, int version)
401 : : {
402 : : struct kern_ipc_perm *ipcp;
403 : 4444 : struct msqid64_ds uninitialized_var(msqid64);
404 : : struct msg_queue *msq;
405 : : int err;
406 : :
407 [ + + ]: 4444 : if (cmd == IPC_SET) {
408 [ + + ]: 2 : if (copy_msqid_from_user(&msqid64, buf, version))
409 : : return -EFAULT;
410 : : }
411 : :
412 : 4443 : down_write(&msg_ids(ns).rwsem);
413 : : rcu_read_lock();
414 : :
415 : 4443 : ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
416 : 4443 : &msqid64.msg_perm, msqid64.msg_qbytes);
417 [ + + ]: 4443 : if (IS_ERR(ipcp)) {
418 : : err = PTR_ERR(ipcp);
419 : 1 : goto out_unlock1;
420 : : }
421 : :
422 : : msq = container_of(ipcp, struct msg_queue, q_perm);
423 : :
424 : 4442 : err = security_msg_queue_msgctl(msq, cmd);
425 [ + - ]: 4442 : if (err)
426 : : goto out_unlock1;
427 : :
428 [ + + - ]: 4442 : switch (cmd) {
429 : : case IPC_RMID:
430 : : ipc_lock_object(&msq->q_perm);
431 : : /* freeque unlocks the ipc object and rcu */
432 : 4441 : freeque(ns, ipcp);
433 : 4441 : goto out_up;
434 : : case IPC_SET:
435 [ - + # # ]: 1 : if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
436 : 0 : !capable(CAP_SYS_RESOURCE)) {
437 : : err = -EPERM;
438 : : goto out_unlock1;
439 : : }
440 : :
441 : : ipc_lock_object(&msq->q_perm);
442 : 1 : err = ipc_update_perm(&msqid64.msg_perm, ipcp);
443 [ + - ]: 1 : if (err)
444 : : goto out_unlock0;
445 : :
446 : 1 : msq->q_qbytes = msqid64.msg_qbytes;
447 : :
448 : 1 : msq->q_ctime = get_seconds();
449 : : /* sleeping receivers might be excluded by
450 : : * stricter permissions.
451 : : */
452 : 1 : expunge_all(msq, -EAGAIN);
453 : : /* sleeping senders might be able to send
454 : : * due to a larger queue size.
455 : : */
456 : 1 : ss_wakeup(&msq->q_senders, 0);
457 : 1 : break;
458 : : default:
459 : : err = -EINVAL;
460 : : goto out_unlock1;
461 : : }
462 : :
463 : : out_unlock0:
464 : : ipc_unlock_object(&msq->q_perm);
465 : : out_unlock1:
466 : : rcu_read_unlock();
467 : : out_up:
468 : 4443 : up_write(&msg_ids(ns).rwsem);
469 : 4443 : return err;
470 : : }
471 : :
472 : 0 : static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
473 : : int cmd, int version, void __user *buf)
474 : : {
475 : : int err;
476 : : struct msg_queue *msq;
477 : :
478 [ + + - ]: 23 : switch (cmd) {
479 : : case IPC_INFO:
480 : : case MSG_INFO:
481 : : {
482 : : struct msginfo msginfo;
483 : : int max_id;
484 : :
485 [ + - ]: 7 : if (!buf)
486 : : return -EFAULT;
487 : :
488 : : /*
489 : : * We must not return kernel stack data.
490 : : * due to padding, it's not enough
491 : : * to set all member fields.
492 : : */
493 : 7 : err = security_msg_queue_msgctl(NULL, cmd);
494 [ + - ]: 7 : if (err)
495 : : return err;
496 : :
497 : 7 : memset(&msginfo, 0, sizeof(msginfo));
498 : 7 : msginfo.msgmni = ns->msg_ctlmni;
499 : 7 : msginfo.msgmax = ns->msg_ctlmax;
500 : 7 : msginfo.msgmnb = ns->msg_ctlmnb;
501 : 7 : msginfo.msgssz = MSGSSZ;
502 : 7 : msginfo.msgseg = MSGSEG;
503 : 7 : down_read(&msg_ids(ns).rwsem);
504 [ + + ]: 7 : if (cmd == MSG_INFO) {
505 : 5 : msginfo.msgpool = msg_ids(ns).in_use;
506 : 5 : msginfo.msgmap = atomic_read(&ns->msg_hdrs);
507 : 5 : msginfo.msgtql = atomic_read(&ns->msg_bytes);
508 : : } else {
509 : 2 : msginfo.msgmap = MSGMAP;
510 : 2 : msginfo.msgpool = MSGPOOL;
511 : 2 : msginfo.msgtql = MSGTQL;
512 : : }
513 : 7 : max_id = ipc_get_maxid(&msg_ids(ns));
514 : 7 : up_read(&msg_ids(ns).rwsem);
515 [ + - ]: 7 : if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
516 : : return -EFAULT;
517 : 7 : return (max_id < 0) ? 0 : max_id;
518 : : }
519 : :
520 : : case MSG_STAT:
521 : : case IPC_STAT:
522 : : {
523 : : struct msqid64_ds tbuf;
524 : : int success_return;
525 : :
526 [ + + ]: 16 : if (!buf)
527 : 9 : return -EFAULT;
528 : :
529 : 15 : memset(&tbuf, 0, sizeof(tbuf));
530 : :
531 : : rcu_read_lock();
532 [ + + ]: 15 : if (cmd == MSG_STAT) {
533 : : msq = msq_obtain_object(ns, msqid);
534 [ + + ]: 5 : if (IS_ERR(msq)) {
535 : : err = PTR_ERR(msq);
536 : 4 : goto out_unlock;
537 : : }
538 : 1 : success_return = msq->q_perm.id;
539 : : } else {
540 : : msq = msq_obtain_object_check(ns, msqid);
541 [ + + ]: 10 : if (IS_ERR(msq)) {
542 : : err = PTR_ERR(msq);
543 : 2 : goto out_unlock;
544 : : }
545 : : success_return = 0;
546 : : }
547 : :
548 : : err = -EACCES;
549 [ + + ]: 9 : if (ipcperms(ns, &msq->q_perm, S_IRUGO))
550 : : goto out_unlock;
551 : :
552 : 8 : err = security_msg_queue_msgctl(msq, cmd);
553 [ + - ]: 8 : if (err)
554 : : goto out_unlock;
555 : :
556 : 8 : kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
557 : 8 : tbuf.msg_stime = msq->q_stime;
558 : 8 : tbuf.msg_rtime = msq->q_rtime;
559 : 8 : tbuf.msg_ctime = msq->q_ctime;
560 : 8 : tbuf.msg_cbytes = msq->q_cbytes;
561 : 8 : tbuf.msg_qnum = msq->q_qnum;
562 : 8 : tbuf.msg_qbytes = msq->q_qbytes;
563 : 8 : tbuf.msg_lspid = msq->q_lspid;
564 : 8 : tbuf.msg_lrpid = msq->q_lrpid;
565 : : rcu_read_unlock();
566 : :
567 [ + + ]: 8 : if (copy_msqid_to_user(buf, &tbuf, version))
568 : : return -EFAULT;
569 : 7 : return success_return;
570 : : }
571 : :
572 : : default:
573 : : return -EINVAL;
574 : : }
575 : :
576 : : return err;
577 : : out_unlock:
578 : : rcu_read_unlock();
579 : 7 : return err;
580 : : }
581 : :
582 : 0 : SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
583 : : {
584 : : int version;
585 : : struct ipc_namespace *ns;
586 : :
587 [ + + ]: 4478 : if (msqid < 0 || cmd < 0)
588 : : return -EINVAL;
589 : :
590 : 4467 : version = ipc_parse_version(&cmd);
591 : 4467 : ns = current->nsproxy->ipc_ns;
592 : :
593 [ + - ][ + + ]: 4467 : switch (cmd) {
[ + - ]
594 : : case IPC_INFO:
595 : : case MSG_INFO:
596 : : case MSG_STAT: /* msqid is an index rather than a msg queue id */
597 : : case IPC_STAT:
598 : 23 : return msgctl_nolock(ns, msqid, cmd, version, buf);
599 : : case IPC_SET:
600 : : case IPC_RMID:
601 : 4444 : return msgctl_down(ns, msqid, cmd, buf, version);
602 : : default:
603 : : return -EINVAL;
604 : : }
605 : : }
606 : :
607 : 215711153 : static int testmsg(struct msg_msg *msg, long type, int mode)
608 : : {
609 [ - + - + ]: 215711153 : switch(mode)
610 : : {
611 : : case SEARCH_ANY:
612 : : case SEARCH_NUMBER:
613 : : return 1;
614 : : case SEARCH_LESSEQUAL:
615 [ # # ]: 0 : if (msg->m_type <=type)
616 : : return 1;
617 : : break;
618 : : case SEARCH_EQUAL:
619 [ + + ]: 215705530 : if (msg->m_type == type)
620 : : return 1;
621 : : break;
622 : : case SEARCH_NOTEQUAL:
623 [ # # ]: 192635747 : if (msg->m_type != type)
624 : : return 1;
625 : : break;
626 : : }
627 : : return 0;
628 : : }
629 : :
630 : : static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
631 : : {
632 : : struct msg_receiver *msr, *t;
633 : :
634 [ + + ]: 40219754 : list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
635 [ + + + + ]: 16934088 : if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
636 : 135991 : !security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
637 : : msr->r_msgtype, msr->r_mode)) {
638 : :
639 : : list_del(&msr->r_list);
640 [ - + ]: 135989 : if (msr->r_maxsize < msg->m_ts) {
641 : 0 : msr->r_msg = NULL;
642 : 0 : wake_up_process(msr->r_tsk);
643 : 0 : smp_mb();
644 : 0 : msr->r_msg = ERR_PTR(-E2BIG);
645 : : } else {
646 : 135989 : msr->r_msg = NULL;
647 : 271974 : msq->q_lrpid = task_pid_vnr(msr->r_tsk);
648 : 135985 : msq->q_rtime = get_seconds();
649 : 135985 : wake_up_process(msr->r_tsk);
650 : 135992 : smp_mb();
651 : 135992 : msr->r_msg = msg;
652 : :
653 : : return 1;
654 : : }
655 : : }
656 : : }
657 : : return 0;
658 : : }
659 : :
660 : 0 : long do_msgsnd(int msqid, long mtype, void __user *mtext,
661 : : size_t msgsz, int msgflg)
662 : : {
663 : : struct msg_queue *msq;
664 : : struct msg_msg *msg;
665 : : int err;
666 : : struct ipc_namespace *ns;
667 : :
668 : 23568183 : ns = current->nsproxy->ipc_ns;
669 : :
670 [ + ][ + ]: 23568183 : if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
671 : : return -EINVAL;
672 [ + + ]: 23570361 : if (mtype < 1)
673 : : return -EINVAL;
674 : :
675 : 23570127 : msg = load_msg(mtext, msgsz);
676 [ - + ]: 23541792 : if (IS_ERR(msg))
677 : 0 : return PTR_ERR(msg);
678 : :
679 : 23541792 : msg->m_type = mtype;
680 : 23541792 : msg->m_ts = msgsz;
681 : :
682 : : rcu_read_lock();
683 : : msq = msq_obtain_object_check(ns, msqid);
684 [ - + ]: 23541454 : if (IS_ERR(msq)) {
685 : : err = PTR_ERR(msq);
686 : 0 : goto out_unlock1;
687 : : }
688 : :
689 : : ipc_lock_object(&msq->q_perm);
690 : :
691 : : for (;;) {
692 : : struct msg_sender s;
693 : :
694 : : err = -EACCES;
695 [ + + ]: 26411333 : if (ipcperms(ns, &msq->q_perm, S_IWUGO))
696 : : goto out_unlock0;
697 : :
698 : : /* raced with RMID? */
699 [ + ]: 26355188 : if (msq->q_perm.deleted) {
700 : : err = -EIDRM;
701 : : goto out_unlock0;
702 : : }
703 : :
704 : 26357717 : err = security_msg_queue_msgsnd(msq, msg, msgflg);
705 [ + ]: 26381000 : if (err)
706 : : goto out_unlock0;
707 : :
708 [ + + ][ + + ]: 26387201 : if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
709 : 23561639 : 1 + msq->q_qnum <= msq->q_qbytes) {
710 : : break;
711 : : }
712 : :
713 : : /* queue full, wait: */
714 [ + ]: 2825742 : if (msgflg & IPC_NOWAIT) {
715 : : err = -EAGAIN;
716 : : goto out_unlock0;
717 : : }
718 : :
719 : : ss_add(msq, &s);
720 : :
721 [ + - ]: 2840828 : if (!ipc_rcu_getref(msq)) {
722 : : err = -EIDRM;
723 : : goto out_unlock0;
724 : : }
725 : :
726 : : ipc_unlock_object(&msq->q_perm);
727 : : rcu_read_unlock();
728 : 2841292 : schedule();
729 : :
730 : : rcu_read_lock();
731 : : ipc_lock_object(&msq->q_perm);
732 : :
733 : 2841596 : ipc_rcu_putref(msq, ipc_rcu_free);
734 [ + + ]: 2841554 : if (msq->q_perm.deleted) {
735 : : err = -EIDRM;
736 : : goto out_unlock0;
737 : : }
738 : :
739 : : ss_del(&s);
740 : :
741 [ + ]: 2841549 : if (signal_pending(current)) {
742 : : err = -ERESTARTNOHAND;
743 : : goto out_unlock0;
744 : : }
745 : :
746 : 2841616 : }
747 : 47126124 : msq->q_lspid = task_tgid_vnr(current);
748 : 23564665 : msq->q_stime = get_seconds();
749 : :
750 [ + + ]: 23557648 : if (!pipelined_send(msq, msg)) {
751 : : /* no one is waiting for this message, enqueue it */
752 : 23427205 : list_add_tail(&msg->m_list, &msq->q_messages);
753 : 23427205 : msq->q_cbytes += msgsz;
754 : 23427205 : msq->q_qnum++;
755 : 23427205 : atomic_add(msgsz, &ns->msg_bytes);
756 : 23452218 : atomic_inc(&ns->msg_hdrs);
757 : : }
758 : :
759 : : err = 0;
760 : : msg = NULL;
761 : :
762 : : out_unlock0:
763 : : ipc_unlock_object(&msq->q_perm);
764 : : out_unlock1:
765 : : rcu_read_unlock();
766 [ + + ]: 23573738 : if (msg != NULL)
767 : 7 : free_msg(msg);
768 : 23575252 : return err;
769 : : }
770 : :
771 : 0 : SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
772 : : int, msgflg)
773 : : {
774 : : long mtype;
775 : :
776 [ + ]: 23549021 : if (get_user(mtype, &msgp->mtype))
777 : : return -EFAULT;
778 : 23555736 : return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
779 : : }
780 : :
781 : : static inline int convert_mode(long *msgtyp, int msgflg)
782 : : {
783 [ + ]: 23551180 : if (msgflg & MSG_COPY)
784 : : return SEARCH_NUMBER;
785 : : /*
786 : : * find message of correct type.
787 : : * msgtyp = 0 => get first.
788 : : * msgtyp > 0 => get first message of matching type.
789 : : * msgtyp < 0 => get message with least type must be < abs(msgtype).
790 : : */
791 [ + ]: 23551283 : if (*msgtyp == 0)
792 : : return SEARCH_ANY;
793 [ - + ]: 23552986 : if (*msgtyp < 0) {
794 : 0 : *msgtyp = -*msgtyp;
795 : : return SEARCH_LESSEQUAL;
796 : : }
797 [ + + ]: 23552986 : if (msgflg & MSG_EXCEPT)
798 : : return SEARCH_NOTEQUAL;
799 : : return SEARCH_EQUAL;
800 : : }
801 : :
802 : 0 : static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
803 : : {
804 : : struct msgbuf __user *msgp = dest;
805 : : size_t msgsz;
806 : :
807 [ + ]: 23564872 : if (put_user(msg->m_type, &msgp->mtype))
808 : : return -EFAULT;
809 : :
810 : 23572318 : msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
811 [ + ]: 23572318 : if (store_msg(msgp->mtext, msg, msgsz))
812 : : return -EFAULT;
813 : 23558725 : return msgsz;
814 : : }
815 : :
816 : : #ifdef CONFIG_CHECKPOINT_RESTORE
817 : : /*
818 : : * This function creates new kernel message structure, large enough to store
819 : : * bufsz message bytes.
820 : : */
821 : : static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
822 : : {
823 : : struct msg_msg *copy;
824 : :
825 : : /*
826 : : * Create dummy message to copy real message to.
827 : : */
828 : : copy = load_msg(buf, bufsz);
829 : : if (!IS_ERR(copy))
830 : : copy->m_ts = bufsz;
831 : : return copy;
832 : : }
833 : :
834 : : static inline void free_copy(struct msg_msg *copy)
835 : : {
836 : : if (copy)
837 : : free_msg(copy);
838 : : }
839 : : #else
840 : : static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
841 : : {
842 : : return ERR_PTR(-ENOSYS);
843 : : }
844 : :
845 : : static inline void free_copy(struct msg_msg *copy)
846 : : {
847 : : }
848 : : #endif
849 : :
850 : 0 : static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
851 : : {
852 : : struct msg_msg *msg, *found = NULL;
853 : : long count = 0;
854 : :
855 [ + + ]: 200116985 : list_for_each_entry(msg, &msq->q_messages, m_list) {
856 [ + + + ]: 223417924 : if (testmsg(msg, *msgtyp, mode) &&
857 : 23412763 : !security_msg_queue_msgrcv(msq, msg, current,
858 : : *msgtyp, mode)) {
859 [ - + ][ # # ]: 23437186 : if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
860 : 0 : *msgtyp = msg->m_type - 1;
861 : 0 : found = msg;
862 [ - + ]: 23437186 : } else if (mode == SEARCH_NUMBER) {
863 [ # # ]: 0 : if (*msgtyp == count)
864 : : return msg;
865 : : } else
866 : : return msg;
867 : 0 : count++;
868 : : }
869 : : }
870 : :
871 [ - + ]: 135988 : return found ?: ERR_PTR(-EAGAIN);
872 : : }
873 : :
874 : 0 : long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
875 : : long (*msg_handler)(void __user *, struct msg_msg *, size_t))
876 : : {
877 : : int mode;
878 : : struct msg_queue *msq;
879 : : struct ipc_namespace *ns;
880 : : struct msg_msg *msg, *copy = NULL;
881 : :
882 : 23524611 : ns = current->nsproxy->ipc_ns;
883 : :
884 [ + ]: 23524611 : if (msqid < 0 || (long) bufsz < 0)
885 : : return -EINVAL;
886 : :
887 [ + ]: 23549573 : if (msgflg & MSG_COPY) {
888 : : copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
889 : : if (IS_ERR(copy))
890 : : return PTR_ERR(copy);
891 : : }
892 : : mode = convert_mode(&msgtyp, msgflg);
893 : :
894 : : rcu_read_lock();
895 : : msq = msq_obtain_object_check(ns, msqid);
896 [ + - ]: 23548329 : if (IS_ERR(msq)) {
897 : : rcu_read_unlock();
898 : : free_copy(copy);
899 : 0 : return PTR_ERR(msq);
900 : : }
901 : :
902 : : for (;;) {
903 : : struct msg_receiver msr_d;
904 : :
905 : : msg = ERR_PTR(-EACCES);
906 [ + - ]: 23548329 : if (ipcperms(ns, &msq->q_perm, S_IRUGO))
907 : : goto out_unlock1;
908 : :
909 : : ipc_lock_object(&msq->q_perm);
910 : :
911 : : /* raced with RMID? */
912 [ + ]: 23569079 : if (msq->q_perm.deleted) {
913 : : msg = ERR_PTR(-EIDRM);
914 : 23435120 : goto out_unlock0;
915 : : }
916 : :
917 : 23569298 : msg = find_msg(msq, &msgtyp, mode);
918 [ + + ]: 23561303 : if (!IS_ERR(msg)) {
919 : : /*
920 : : * Found a suitable message.
921 : : * Unlink it from the queue.
922 : : */
923 [ + + ][ + ]: 23425313 : if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
924 : : msg = ERR_PTR(-E2BIG);
925 : : goto out_unlock0;
926 : : }
927 : : /*
928 : : * If we are copying, then do not unlink message and do
929 : : * not update queue parameters.
930 : : */
931 [ - + ]: 23424570 : if (msgflg & MSG_COPY) {
932 : 0 : msg = copy_msg(msg, copy);
933 : 0 : goto out_unlock0;
934 : : }
935 : :
936 : : list_del(&msg->m_list);
937 : 23424570 : msq->q_qnum--;
938 : 23424570 : msq->q_rtime = get_seconds();
939 : 46841132 : msq->q_lrpid = task_tgid_vnr(current);
940 : 23411882 : msq->q_cbytes -= msg->m_ts;
941 : 23411882 : atomic_sub(msg->m_ts, &ns->msg_bytes);
942 : 23444761 : atomic_dec(&ns->msg_hdrs);
943 : 23438885 : ss_wakeup(&msq->q_senders, 0);
944 : :
945 : 23434595 : goto out_unlock0;
946 : : }
947 : :
948 : : /* No message waiting. Wait for a message */
949 [ + - ]: 135990 : if (msgflg & IPC_NOWAIT) {
950 : : msg = ERR_PTR(-ENOMSG);
951 : : goto out_unlock0;
952 : : }
953 : :
954 : 135990 : list_add_tail(&msr_d.r_list, &msq->q_receivers);
955 : 135990 : msr_d.r_tsk = current;
956 : 135990 : msr_d.r_msgtype = msgtyp;
957 : 135990 : msr_d.r_mode = mode;
958 [ - + ]: 135990 : if (msgflg & MSG_NOERROR)
959 : 0 : msr_d.r_maxsize = INT_MAX;
960 : : else
961 : 135990 : msr_d.r_maxsize = bufsz;
962 : 135990 : msr_d.r_msg = ERR_PTR(-EAGAIN);
963 : 135990 : current->state = TASK_INTERRUPTIBLE;
964 : :
965 : : ipc_unlock_object(&msq->q_perm);
966 : : rcu_read_unlock();
967 : 135987 : schedule();
968 : :
969 : : /* Lockless receive, part 1:
970 : : * Disable preemption. We don't hold a reference to the queue
971 : : * and getting a reference would defeat the idea of a lockless
972 : : * operation, thus the code relies on rcu to guarantee the
973 : : * existence of msq:
974 : : * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
975 : : * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
976 : : * rcu_read_lock() prevents preemption between reading r_msg
977 : : * and acquiring the q_perm.lock in ipc_lock_object().
978 : : */
979 : : rcu_read_lock();
980 : :
981 : : /* Lockless receive, part 2:
982 : : * Wait until pipelined_send or expunge_all are outside of
983 : : * wake_up_process(). There is a race with exit(), see
984 : : * ipc/mqueue.c for the details.
985 : : */
986 : 135993 : msg = (struct msg_msg*)msr_d.r_msg;
987 [ - + ]: 135993 : while (msg == NULL) {
988 : 0 : cpu_relax();
989 : 0 : msg = (struct msg_msg *)msr_d.r_msg;
990 : : }
991 : :
992 : : /* Lockless receive, part 3:
993 : : * If there is a message or an error then accept it without
994 : : * locking.
995 : : */
996 [ + + ]: 135993 : if (msg != ERR_PTR(-EAGAIN))
997 : : goto out_unlock1;
998 : :
999 : : /* Lockless receive, part 3:
1000 : : * Acquire the queue spinlock.
1001 : : */
1002 : : ipc_lock_object(&msq->q_perm);
1003 : :
1004 : : /* Lockless receive, part 4:
1005 : : * Repeat test after acquiring the spinlock.
1006 : : */
1007 : 1 : msg = (struct msg_msg*)msr_d.r_msg;
1008 [ + - ]: 1 : if (msg != ERR_PTR(-EAGAIN))
1009 : : goto out_unlock0;
1010 : :
1011 : : list_del(&msr_d.r_list);
1012 [ - + ]: 1 : if (signal_pending(current)) {
1013 : : msg = ERR_PTR(-ERESTARTNOHAND);
1014 : : goto out_unlock0;
1015 : : }
1016 : :
1017 : : ipc_unlock_object(&msq->q_perm);
1018 : 135992 : }
1019 : :
1020 : : out_unlock0:
1021 : : ipc_unlock_object(&msq->q_perm);
1022 : : out_unlock1:
1023 : : rcu_read_unlock();
1024 [ + + ]: 23571309 : if (IS_ERR(msg)) {
1025 : : free_copy(copy);
1026 : 5 : return PTR_ERR(msg);
1027 : : }
1028 : :
1029 : 23571304 : bufsz = msg_handler(buf, msg, bufsz);
1030 : 23561081 : free_msg(msg);
1031 : :
1032 : 23579739 : return bufsz;
1033 : : }
1034 : :
1035 : 0 : SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
1036 : : long, msgtyp, int, msgflg)
1037 : : {
1038 : 23531506 : return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
1039 : : }
1040 : :
1041 : : #ifdef CONFIG_PROC_FS
1042 : 0 : static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1043 : : {
1044 : : struct user_namespace *user_ns = seq_user_ns(s);
1045 : : struct msg_queue *msq = it;
1046 : :
1047 : 0 : return seq_printf(s,
1048 : : "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
1049 : : msq->q_perm.key,
1050 : : msq->q_perm.id,
1051 : 0 : msq->q_perm.mode,
1052 : : msq->q_cbytes,
1053 : : msq->q_qnum,
1054 : : msq->q_lspid,
1055 : : msq->q_lrpid,
1056 : : from_kuid_munged(user_ns, msq->q_perm.uid),
1057 : : from_kgid_munged(user_ns, msq->q_perm.gid),
1058 : : from_kuid_munged(user_ns, msq->q_perm.cuid),
1059 : : from_kgid_munged(user_ns, msq->q_perm.cgid),
1060 : : msq->q_stime,
1061 : : msq->q_rtime,
1062 : : msq->q_ctime);
1063 : : }
1064 : : #endif
|