msg.c 22.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 * linux/ipc/msg.c
3
 * Copyright (C) 1992 Krishna Balasubramanian
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14
 *
 * Removed all the remaining kerneld mess
 * Catch the -EFAULT stuff properly
 * Use GFP_KERNEL for messages as in 1.2
 * Fixed up the unchecked user space derefs
 * Copyright (C) 1998 Alan Cox & Andi Kleen
 *
 * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
 *
 * mostly rewritten, threaded and wake-one semantics added
 * MSGMAX limit removed, sysctl's added
15
 * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
S
Steve Grubb 已提交
16 17 18
 *
 * support for audit of ipc object properties and permission changes
 * Dustin Kirkland <dustin.kirkland@us.ibm.com>
K
Kirill Korotaev 已提交
19 20 21 22
 *
 * namespaces support
 * OpenVZ, SWsoft Inc.
 * Pavel Emelianov <xemul@openvz.org>
L
Linus Torvalds 已提交
23 24
 */

25
#include <linux/capability.h>
L
Linus Torvalds 已提交
26 27 28
#include <linux/msg.h>
#include <linux/spinlock.h>
#include <linux/init.h>
29
#include <linux/mm.h>
L
Linus Torvalds 已提交
30 31 32 33 34 35
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/security.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
36
#include <linux/seq_file.h>
N
Nadia Derbey 已提交
37
#include <linux/rwsem.h>
K
Kirill Korotaev 已提交
38
#include <linux/nsproxy.h>
39
#include <linux/ipc_namespace.h>
I
Ingo Molnar 已提交
40

L
Linus Torvalds 已提交
41
#include <asm/current.h>
P
Paul McQuade 已提交
42
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
43 44
#include "util.h"

45
/* one msg_receiver structure for each sleeping receiver */
L
Linus Torvalds 已提交
46
struct msg_receiver {
47 48
	struct list_head	r_list;
	struct task_struct	*r_tsk;
L
Linus Torvalds 已提交
49

50 51 52
	int			r_mode;
	long			r_msgtype;
	long			r_maxsize;
L
Linus Torvalds 已提交
53

54
	struct msg_msg		*r_msg;
L
Linus Torvalds 已提交
55 56 57 58
};

/* one msg_sender for each sleeping sender */
struct msg_sender {
59 60
	struct list_head	list;
	struct task_struct	*tsk;
L
Linus Torvalds 已提交
61 62 63 64 65 66
};

#define SEARCH_ANY		1
#define SEARCH_EQUAL		2
#define SEARCH_NOTEQUAL		3
#define SEARCH_LESSEQUAL	4
67
#define SEARCH_NUMBER		5
L
Linus Torvalds 已提交
68

69
#define msg_ids(ns)	((ns)->ids[IPC_MSG_IDS])
L
Linus Torvalds 已提交
70

71 72
static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id)
{
D
Davidlohr Bueso 已提交
73
	struct kern_ipc_perm *ipcp = ipc_obtain_object_idr(&msg_ids(ns), id);
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

	if (IS_ERR(ipcp))
		return ERR_CAST(ipcp);

	return container_of(ipcp, struct msg_queue, q_perm);
}

static inline struct msg_queue *msq_obtain_object_check(struct ipc_namespace *ns,
							int id)
{
	struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&msg_ids(ns), id);

	if (IS_ERR(ipcp))
		return ERR_CAST(ipcp);

	return container_of(ipcp, struct msg_queue, q_perm);
}

N
Nadia Derbey 已提交
92 93 94 95 96
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
{
	ipc_rmid(&msg_ids(ns), &s->q_perm);
}

D
Davidlohr Bueso 已提交
97 98 99 100 101 102 103 104 105
static void msg_rcu_free(struct rcu_head *head)
{
	struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
	struct msg_queue *msq = ipc_rcu_to_struct(p);

	security_msg_queue_free(msq);
	ipc_rcu_free(head);
}

N
Nadia Derbey 已提交
106 107 108 109 110
/**
 * newque - Create a new msg queue
 * @ns: namespace
 * @params: ptr to the structure that contains the key and msgflg
 *
D
Davidlohr Bueso 已提交
111
 * Called with msg_ids.rwsem held (writer)
N
Nadia Derbey 已提交
112
 */
N
Nadia Derbey 已提交
113
static int newque(struct ipc_namespace *ns, struct ipc_params *params)
L
Linus Torvalds 已提交
114 115
{
	struct msg_queue *msq;
116
	int id, retval;
N
Nadia Derbey 已提交
117 118
	key_t key = params->key;
	int msgflg = params->flg;
L
Linus Torvalds 已提交
119

120 121
	msq = ipc_rcu_alloc(sizeof(*msq));
	if (!msq)
L
Linus Torvalds 已提交
122 123
		return -ENOMEM;

124
	msq->q_perm.mode = msgflg & S_IRWXUGO;
L
Linus Torvalds 已提交
125 126 127 128 129
	msq->q_perm.key = key;

	msq->q_perm.security = NULL;
	retval = security_msg_queue_alloc(msq);
	if (retval) {
D
Davidlohr Bueso 已提交
130
		ipc_rcu_putref(msq, ipc_rcu_free);
L
Linus Torvalds 已提交
131 132 133 134 135 136
		return retval;
	}

	msq->q_stime = msq->q_rtime = 0;
	msq->q_ctime = get_seconds();
	msq->q_cbytes = msq->q_qnum = 0;
K
Kirill Korotaev 已提交
137
	msq->q_qbytes = ns->msg_ctlmnb;
L
Linus Torvalds 已提交
138 139 140 141
	msq->q_lspid = msq->q_lrpid = 0;
	INIT_LIST_HEAD(&msq->q_messages);
	INIT_LIST_HEAD(&msq->q_receivers);
	INIT_LIST_HEAD(&msq->q_senders);
N
Nadia Derbey 已提交
142

143 144 145 146 147 148 149
	/* ipc_addid() locks msq upon success. */
	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
	if (id < 0) {
		ipc_rcu_putref(msq, msg_rcu_free);
		return id;
	}

150
	ipc_unlock_object(&msq->q_perm);
151
	rcu_read_unlock();
L
Linus Torvalds 已提交
152

N
Nadia Derbey 已提交
153
	return msq->q_perm.id;
L
Linus Torvalds 已提交
154 155
}

156
static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
L
Linus Torvalds 已提交
157
{
158
	mss->tsk = current;
159
	__set_current_state(TASK_INTERRUPTIBLE);
160
	list_add_tail(&mss->list, &msq->q_senders);
L
Linus Torvalds 已提交
161 162
}

163
static inline void ss_del(struct msg_sender *mss)
L
Linus Torvalds 已提交
164
{
165
	if (mss->list.next != NULL)
L
Linus Torvalds 已提交
166 167 168
		list_del(&mss->list);
}

169
static void ss_wakeup(struct list_head *h, int kill)
L
Linus Torvalds 已提交
170
{
171
	struct msg_sender *mss, *t;
L
Linus Torvalds 已提交
172

173
	list_for_each_entry_safe(mss, t, h, list) {
174 175
		if (kill)
			mss->list.next = NULL;
L
Linus Torvalds 已提交
176 177 178 179
		wake_up_process(mss->tsk);
	}
}

180 181
static void expunge_all(struct msg_queue *msq, int res,
			struct wake_q_head *wake_q)
L
Linus Torvalds 已提交
182
{
183
	struct msg_receiver *msr, *t;
184

185
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
186 187
		wake_q_add(wake_q, msr->r_tsk);
		WRITE_ONCE(msr->r_msg, ERR_PTR(res));
L
Linus Torvalds 已提交
188 189
	}
}
190 191 192

/*
 * freeque() wakes up waiters on the sender and receiver waiting queue,
N
Nadia Derbey 已提交
193 194
 * removes the message queue from message queue ID IDR, and cleans up all the
 * messages associated with this queue.
L
Linus Torvalds 已提交
195
 *
D
Davidlohr Bueso 已提交
196 197
 * msg_ids.rwsem (writer) and the spinlock for this message queue are held
 * before freeque() is called. msg_ids.rwsem remains locked on exit.
L
Linus Torvalds 已提交
198
 */
199
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
L
Linus Torvalds 已提交
200
{
201
	struct msg_msg *msg, *t;
202
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
203
	WAKE_Q(wake_q);
L
Linus Torvalds 已提交
204

205
	expunge_all(msq, -EIDRM, &wake_q);
206
	ss_wakeup(&msq->q_senders, 1);
N
Nadia Derbey 已提交
207
	msg_rmid(ns, msq);
D
Davidlohr Bueso 已提交
208
	ipc_unlock_object(&msq->q_perm);
209
	wake_up_q(&wake_q);
D
Davidlohr Bueso 已提交
210
	rcu_read_unlock();
211

212
	list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
213
		atomic_dec(&ns->msg_hdrs);
L
Linus Torvalds 已提交
214 215
		free_msg(msg);
	}
216
	atomic_sub(msq->q_cbytes, &ns->msg_bytes);
D
Davidlohr Bueso 已提交
217
	ipc_rcu_putref(msq, msg_rcu_free);
L
Linus Torvalds 已提交
218 219
}

N
Nadia Derbey 已提交
220
/*
D
Davidlohr Bueso 已提交
221
 * Called with msg_ids.rwsem and ipcp locked.
N
Nadia Derbey 已提交
222
 */
N
Nadia Derbey 已提交
223
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
N
Nadia Derbey 已提交
224
{
N
Nadia Derbey 已提交
225 226 227
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);

	return security_msg_queue_associate(msq, msgflg);
N
Nadia Derbey 已提交
228 229
}

230
SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
L
Linus Torvalds 已提交
231
{
K
Kirill Korotaev 已提交
232
	struct ipc_namespace *ns;
M
Mathias Krause 已提交
233 234 235 236
	static const struct ipc_ops msg_ops = {
		.getnew = newque,
		.associate = msg_security,
	};
N
Nadia Derbey 已提交
237
	struct ipc_params msg_params;
K
Kirill Korotaev 已提交
238 239

	ns = current->nsproxy->ipc_ns;
N
Nadia Derbey 已提交
240

N
Nadia Derbey 已提交
241 242
	msg_params.key = key;
	msg_params.flg = msgflg;
243

N
Nadia Derbey 已提交
244
	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
L
Linus Torvalds 已提交
245 246
}

247 248
static inline unsigned long
copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
L
Linus Torvalds 已提交
249
{
M
Manfred Spraul 已提交
250
	switch (version) {
L
Linus Torvalds 已提交
251
	case IPC_64:
252
		return copy_to_user(buf, in, sizeof(*in));
L
Linus Torvalds 已提交
253
	case IPC_OLD:
254
	{
L
Linus Torvalds 已提交
255 256
		struct msqid_ds out;

257
		memset(&out, 0, sizeof(out));
L
Linus Torvalds 已提交
258 259 260 261 262 263 264

		ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);

		out.msg_stime		= in->msg_stime;
		out.msg_rtime		= in->msg_rtime;
		out.msg_ctime		= in->msg_ctime;

265 266
		if (in->msg_cbytes > USHRT_MAX)
			out.msg_cbytes	= USHRT_MAX;
L
Linus Torvalds 已提交
267 268 269 270
		else
			out.msg_cbytes	= in->msg_cbytes;
		out.msg_lcbytes		= in->msg_cbytes;

271 272
		if (in->msg_qnum > USHRT_MAX)
			out.msg_qnum	= USHRT_MAX;
L
Linus Torvalds 已提交
273 274 275
		else
			out.msg_qnum	= in->msg_qnum;

276 277
		if (in->msg_qbytes > USHRT_MAX)
			out.msg_qbytes	= USHRT_MAX;
L
Linus Torvalds 已提交
278 279 280 281 282 283 284
		else
			out.msg_qbytes	= in->msg_qbytes;
		out.msg_lqbytes		= in->msg_qbytes;

		out.msg_lspid		= in->msg_lspid;
		out.msg_lrpid		= in->msg_lrpid;

285 286
		return copy_to_user(buf, &out, sizeof(out));
	}
L
Linus Torvalds 已提交
287 288 289 290 291
	default:
		return -EINVAL;
	}
}

292
static inline unsigned long
293
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
L
Linus Torvalds 已提交
294
{
M
Manfred Spraul 已提交
295
	switch (version) {
L
Linus Torvalds 已提交
296
	case IPC_64:
297
		if (copy_from_user(out, buf, sizeof(*out)))
L
Linus Torvalds 已提交
298 299 300
			return -EFAULT;
		return 0;
	case IPC_OLD:
301
	{
L
Linus Torvalds 已提交
302 303
		struct msqid_ds tbuf_old;

304
		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
L
Linus Torvalds 已提交
305 306
			return -EFAULT;

M
Manfred Spraul 已提交
307 308 309
		out->msg_perm.uid	= tbuf_old.msg_perm.uid;
		out->msg_perm.gid	= tbuf_old.msg_perm.gid;
		out->msg_perm.mode	= tbuf_old.msg_perm.mode;
L
Linus Torvalds 已提交
310

311
		if (tbuf_old.msg_qbytes == 0)
312
			out->msg_qbytes	= tbuf_old.msg_lqbytes;
L
Linus Torvalds 已提交
313
		else
314
			out->msg_qbytes	= tbuf_old.msg_qbytes;
L
Linus Torvalds 已提交
315 316

		return 0;
317
	}
L
Linus Torvalds 已提交
318 319 320 321 322
	default:
		return -EINVAL;
	}
}

323
/*
D
Davidlohr Bueso 已提交
324
 * This function handles some msgctl commands which require the rwsem
325
 * to be held in write mode.
D
Davidlohr Bueso 已提交
326
 * NOTE: no locks must be held, the rwsem is taken inside this function.
327 328 329
 */
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
		       struct msqid_ds __user *buf, int version)
L
Linus Torvalds 已提交
330 331
{
	struct kern_ipc_perm *ipcp;
332
	struct msqid64_ds uninitialized_var(msqid64);
333
	struct msg_queue *msq;
334
	WAKE_Q(wake_q);
335 336 337
	int err;

	if (cmd == IPC_SET) {
338
		if (copy_msqid_from_user(&msqid64, buf, version))
339 340 341
			return -EFAULT;
	}

D
Davidlohr Bueso 已提交
342
	down_write(&msg_ids(ns).rwsem);
343 344
	rcu_read_lock();

345 346
	ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
				      &msqid64.msg_perm, msqid64.msg_qbytes);
347 348 349 350
	if (IS_ERR(ipcp)) {
		err = PTR_ERR(ipcp);
		goto out_unlock1;
	}
351

352
	msq = container_of(ipcp, struct msg_queue, q_perm);
353 354 355

	err = security_msg_queue_msgctl(msq, cmd);
	if (err)
356
		goto out_unlock1;
357 358 359

	switch (cmd) {
	case IPC_RMID:
360
		ipc_lock_object(&msq->q_perm);
361
		/* freeque unlocks the ipc object and rcu */
362 363 364
		freeque(ns, ipcp);
		goto out_up;
	case IPC_SET:
365
		if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
366 367
		    !capable(CAP_SYS_RESOURCE)) {
			err = -EPERM;
368
			goto out_unlock1;
369 370
		}

371
		ipc_lock_object(&msq->q_perm);
372 373
		err = ipc_update_perm(&msqid64.msg_perm, ipcp);
		if (err)
374
			goto out_unlock0;
375

376
		msq->q_qbytes = msqid64.msg_qbytes;
377 378 379 380 381

		msq->q_ctime = get_seconds();
		/* sleeping receivers might be excluded by
		 * stricter permissions.
		 */
382
		expunge_all(msq, -EAGAIN, &wake_q);
383 384 385 386 387 388 389
		/* sleeping senders might be able to send
		 * due to a larger queue size.
		 */
		ss_wakeup(&msq->q_senders, 0);
		break;
	default:
		err = -EINVAL;
390
		goto out_unlock1;
391
	}
392 393 394

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
395
	wake_up_q(&wake_q);
396 397
out_unlock1:
	rcu_read_unlock();
398
out_up:
D
Davidlohr Bueso 已提交
399
	up_write(&msg_ids(ns).rwsem);
400 401 402
	return err;
}

403 404
static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
			 int cmd, int version, void __user *buf)
405
{
406
	int err;
407
	struct msg_queue *msq;
L
Linus Torvalds 已提交
408 409

	switch (cmd) {
410 411 412
	case IPC_INFO:
	case MSG_INFO:
	{
L
Linus Torvalds 已提交
413 414
		struct msginfo msginfo;
		int max_id;
415

L
Linus Torvalds 已提交
416 417
		if (!buf)
			return -EFAULT;
418

419 420
		/*
		 * We must not return kernel stack data.
L
Linus Torvalds 已提交
421 422 423 424 425 426 427
		 * due to padding, it's not enough
		 * to set all member fields.
		 */
		err = security_msg_queue_msgctl(NULL, cmd);
		if (err)
			return err;

428
		memset(&msginfo, 0, sizeof(msginfo));
K
Kirill Korotaev 已提交
429 430 431
		msginfo.msgmni = ns->msg_ctlmni;
		msginfo.msgmax = ns->msg_ctlmax;
		msginfo.msgmnb = ns->msg_ctlmnb;
L
Linus Torvalds 已提交
432 433
		msginfo.msgssz = MSGSSZ;
		msginfo.msgseg = MSGSEG;
D
Davidlohr Bueso 已提交
434
		down_read(&msg_ids(ns).rwsem);
L
Linus Torvalds 已提交
435
		if (cmd == MSG_INFO) {
K
Kirill Korotaev 已提交
436
			msginfo.msgpool = msg_ids(ns).in_use;
437 438
			msginfo.msgmap = atomic_read(&ns->msg_hdrs);
			msginfo.msgtql = atomic_read(&ns->msg_bytes);
L
Linus Torvalds 已提交
439 440 441 442 443
		} else {
			msginfo.msgmap = MSGMAP;
			msginfo.msgpool = MSGPOOL;
			msginfo.msgtql = MSGTQL;
		}
N
Nadia Derbey 已提交
444
		max_id = ipc_get_maxid(&msg_ids(ns));
D
Davidlohr Bueso 已提交
445
		up_read(&msg_ids(ns).rwsem);
446
		if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
L
Linus Torvalds 已提交
447
			return -EFAULT;
448
		return (max_id < 0) ? 0 : max_id;
L
Linus Torvalds 已提交
449
	}
450 451

	case MSG_STAT:
L
Linus Torvalds 已提交
452 453 454 455
	case IPC_STAT:
	{
		struct msqid64_ds tbuf;
		int success_return;
456

L
Linus Torvalds 已提交
457 458 459
		if (!buf)
			return -EFAULT;

460 461 462
		memset(&tbuf, 0, sizeof(tbuf));

		rcu_read_lock();
463
		if (cmd == MSG_STAT) {
464 465 466 467 468
			msq = msq_obtain_object(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
N
Nadia Derbey 已提交
469
			success_return = msq->q_perm.id;
L
Linus Torvalds 已提交
470
		} else {
471 472 473 474 475
			msq = msq_obtain_object_check(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
L
Linus Torvalds 已提交
476 477
			success_return = 0;
		}
478

L
Linus Torvalds 已提交
479
		err = -EACCES;
480
		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
			goto out_unlock;

		err = security_msg_queue_msgctl(msq, cmd);
		if (err)
			goto out_unlock;

		kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
		tbuf.msg_stime  = msq->q_stime;
		tbuf.msg_rtime  = msq->q_rtime;
		tbuf.msg_ctime  = msq->q_ctime;
		tbuf.msg_cbytes = msq->q_cbytes;
		tbuf.msg_qnum   = msq->q_qnum;
		tbuf.msg_qbytes = msq->q_qbytes;
		tbuf.msg_lspid  = msq->q_lspid;
		tbuf.msg_lrpid  = msq->q_lrpid;
496 497
		rcu_read_unlock();

L
Linus Torvalds 已提交
498 499 500 501
		if (copy_msqid_to_user(buf, &tbuf, version))
			return -EFAULT;
		return success_return;
	}
502

L
Linus Torvalds 已提交
503
	default:
504
		return -EINVAL;
L
Linus Torvalds 已提交
505 506
	}

507
	return err;
L
Linus Torvalds 已提交
508
out_unlock:
509
	rcu_read_unlock();
L
Linus Torvalds 已提交
510 511 512
	return err;
}

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
{
	int version;
	struct ipc_namespace *ns;

	if (msqid < 0 || cmd < 0)
		return -EINVAL;

	version = ipc_parse_version(&cmd);
	ns = current->nsproxy->ipc_ns;

	switch (cmd) {
	case IPC_INFO:
	case MSG_INFO:
	case MSG_STAT:	/* msqid is an index rather than a msg queue id */
	case IPC_STAT:
		return msgctl_nolock(ns, msqid, cmd, version, buf);
	case IPC_SET:
	case IPC_RMID:
		return msgctl_down(ns, msqid, cmd, buf, version);
	default:
		return  -EINVAL;
	}
}

538
static int testmsg(struct msg_msg *msg, long type, int mode)
L
Linus Torvalds 已提交
539
{
P
Paul McQuade 已提交
540 541 542 543 544 545 546 547 548 549
	switch (mode) {
	case SEARCH_ANY:
	case SEARCH_NUMBER:
		return 1;
	case SEARCH_LESSEQUAL:
		if (msg->m_type <= type)
			return 1;
		break;
	case SEARCH_EQUAL:
		if (msg->m_type == type)
L
Linus Torvalds 已提交
550
			return 1;
P
Paul McQuade 已提交
551 552 553 554 555
		break;
	case SEARCH_NOTEQUAL:
		if (msg->m_type != type)
			return 1;
		break;
L
Linus Torvalds 已提交
556 557 558 559
	}
	return 0;
}

560 561
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
				 struct wake_q_head *wake_q)
L
Linus Torvalds 已提交
562
{
563
	struct msg_receiver *msr, *t;
564

565
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
566 567 568 569
		if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
		    !security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
					       msr->r_msgtype, msr->r_mode)) {

L
Linus Torvalds 已提交
570
			list_del(&msr->r_list);
571
			if (msr->r_maxsize < msg->m_ts) {
572 573
				wake_q_add(wake_q, msr->r_tsk);
				WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
L
Linus Torvalds 已提交
574
			} else {
575
				msq->q_lrpid = task_pid_vnr(msr->r_tsk);
L
Linus Torvalds 已提交
576
				msq->q_rtime = get_seconds();
577

578 579
				wake_q_add(wake_q, msr->r_tsk);
				WRITE_ONCE(msr->r_msg, msg);
L
Linus Torvalds 已提交
580 581 582 583
				return 1;
			}
		}
	}
D
Davidlohr Bueso 已提交
584

L
Linus Torvalds 已提交
585 586 587
	return 0;
}

588 589
long do_msgsnd(int msqid, long mtype, void __user *mtext,
		size_t msgsz, int msgflg)
L
Linus Torvalds 已提交
590 591 592 593
{
	struct msg_queue *msq;
	struct msg_msg *msg;
	int err;
K
Kirill Korotaev 已提交
594
	struct ipc_namespace *ns;
595
	WAKE_Q(wake_q);
K
Kirill Korotaev 已提交
596 597

	ns = current->nsproxy->ipc_ns;
598

K
Kirill Korotaev 已提交
599
	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
L
Linus Torvalds 已提交
600 601 602 603
		return -EINVAL;
	if (mtype < 1)
		return -EINVAL;

604
	msg = load_msg(mtext, msgsz);
605
	if (IS_ERR(msg))
L
Linus Torvalds 已提交
606 607 608 609 610
		return PTR_ERR(msg);

	msg->m_type = mtype;
	msg->m_ts = msgsz;

611 612
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
613 614
	if (IS_ERR(msq)) {
		err = PTR_ERR(msq);
615
		goto out_unlock1;
616
	}
L
Linus Torvalds 已提交
617

618 619
	ipc_lock_object(&msq->q_perm);

L
Linus Torvalds 已提交
620 621 622
	for (;;) {
		struct msg_sender s;

623
		err = -EACCES;
624
		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
625
			goto out_unlock0;
L
Linus Torvalds 已提交
626

627
		/* raced with RMID? */
628
		if (!ipc_valid_object(&msq->q_perm)) {
629 630 631 632
			err = -EIDRM;
			goto out_unlock0;
		}

L
Linus Torvalds 已提交
633 634
		err = security_msg_queue_msgsnd(msq, msg, msgflg);
		if (err)
635
			goto out_unlock0;
L
Linus Torvalds 已提交
636

637
		if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
L
Linus Torvalds 已提交
638 639 640 641 642
				1 + msq->q_qnum <= msq->q_qbytes) {
			break;
		}

		/* queue full, wait: */
643 644
		if (msgflg & IPC_NOWAIT) {
			err = -EAGAIN;
645
			goto out_unlock0;
L
Linus Torvalds 已提交
646
		}
647

D
Davidlohr Bueso 已提交
648
		/* enqueue the sender and prepare to block */
L
Linus Torvalds 已提交
649
		ss_add(msq, &s);
650 651 652

		if (!ipc_rcu_getref(msq)) {
			err = -EIDRM;
653
			goto out_unlock0;
654 655
		}

656 657
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
L
Linus Torvalds 已提交
658 659
		schedule();

660 661 662
		rcu_read_lock();
		ipc_lock_object(&msq->q_perm);

663
		ipc_rcu_putref(msq, msg_rcu_free);
664 665
		/* raced with RMID? */
		if (!ipc_valid_object(&msq->q_perm)) {
L
Linus Torvalds 已提交
666
			err = -EIDRM;
667
			goto out_unlock0;
L
Linus Torvalds 已提交
668 669
		}
		ss_del(&s);
670

L
Linus Torvalds 已提交
671
		if (signal_pending(current)) {
672
			err = -ERESTARTNOHAND;
673
			goto out_unlock0;
L
Linus Torvalds 已提交
674
		}
675

L
Linus Torvalds 已提交
676
	}
677
	msq->q_lspid = task_tgid_vnr(current);
L
Linus Torvalds 已提交
678 679
	msq->q_stime = get_seconds();

680
	if (!pipelined_send(msq, msg, &wake_q)) {
L
Lucas De Marchi 已提交
681
		/* no one is waiting for this message, enqueue it */
682
		list_add_tail(&msg->m_list, &msq->q_messages);
L
Linus Torvalds 已提交
683 684
		msq->q_cbytes += msgsz;
		msq->q_qnum++;
685 686
		atomic_add(msgsz, &ns->msg_bytes);
		atomic_inc(&ns->msg_hdrs);
L
Linus Torvalds 已提交
687
	}
688

L
Linus Torvalds 已提交
689 690 691
	err = 0;
	msg = NULL;

692 693
out_unlock0:
	ipc_unlock_object(&msq->q_perm);
694
	wake_up_q(&wake_q);
695 696
out_unlock1:
	rcu_read_unlock();
697
	if (msg != NULL)
L
Linus Torvalds 已提交
698 699 700 701
		free_msg(msg);
	return err;
}

702 703
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		int, msgflg)
704 705 706 707 708 709 710 711
{
	long mtype;

	if (get_user(mtype, &msgp->mtype))
		return -EFAULT;
	return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
}

712
static inline int convert_mode(long *msgtyp, int msgflg)
L
Linus Torvalds 已提交
713
{
714 715
	if (msgflg & MSG_COPY)
		return SEARCH_NUMBER;
716
	/*
L
Linus Torvalds 已提交
717 718 719
	 *  find message of correct type.
	 *  msgtyp = 0 => get first.
	 *  msgtyp > 0 => get first message of matching type.
720
	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).
L
Linus Torvalds 已提交
721
	 */
722
	if (*msgtyp == 0)
L
Linus Torvalds 已提交
723
		return SEARCH_ANY;
724 725
	if (*msgtyp < 0) {
		*msgtyp = -*msgtyp;
L
Linus Torvalds 已提交
726 727
		return SEARCH_LESSEQUAL;
	}
728
	if (msgflg & MSG_EXCEPT)
L
Linus Torvalds 已提交
729 730 731 732
		return SEARCH_NOTEQUAL;
	return SEARCH_EQUAL;
}

733 734 735 736 737 738 739 740 741 742 743 744 745 746
static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
	struct msgbuf __user *msgp = dest;
	size_t msgsz;

	if (put_user(msg->m_type, &msgp->mtype))
		return -EFAULT;

	msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
	if (store_msg(msgp->mtext, msg, msgsz))
		return -EFAULT;
	return msgsz;
}

747
#ifdef CONFIG_CHECKPOINT_RESTORE
748 749 750 751
/*
 * This function creates new kernel message structure, large enough to store
 * bufsz message bytes.
 */
752
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
753 754 755 756 757 758 759 760 761 762 763 764
{
	struct msg_msg *copy;

	/*
	 * Create dummy message to copy real message to.
	 */
	copy = load_msg(buf, bufsz);
	if (!IS_ERR(copy))
		copy->m_ts = bufsz;
	return copy;
}

765
static inline void free_copy(struct msg_msg *copy)
766
{
767
	if (copy)
768 769 770
		free_msg(copy);
}
#else
771
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
772 773 774 775
{
	return ERR_PTR(-ENOSYS);
}

776 777 778
static inline void free_copy(struct msg_msg *copy)
{
}
779 780
#endif

781 782
static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
{
783
	struct msg_msg *msg, *found = NULL;
784 785 786 787 788 789 790 791
	long count = 0;

	list_for_each_entry(msg, &msq->q_messages, m_list) {
		if (testmsg(msg, *msgtyp, mode) &&
		    !security_msg_queue_msgrcv(msq, msg, current,
					       *msgtyp, mode)) {
			if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
				*msgtyp = msg->m_type - 1;
792
				found = msg;
793 794 795 796 797 798 799 800 801
			} else if (mode == SEARCH_NUMBER) {
				if (*msgtyp == count)
					return msg;
			} else
				return msg;
			count++;
		}
	}

802
	return found ?: ERR_PTR(-EAGAIN);
803 804
}

805
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
806
	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
L
Linus Torvalds 已提交
807 808
{
	int mode;
809
	struct msg_queue *msq;
K
Kirill Korotaev 已提交
810
	struct ipc_namespace *ns;
811
	struct msg_msg *msg, *copy = NULL;
L
Linus Torvalds 已提交
812

813 814
	ns = current->nsproxy->ipc_ns;

815
	if (msqid < 0 || (long) bufsz < 0)
L
Linus Torvalds 已提交
816
		return -EINVAL;
817

818
	if (msgflg & MSG_COPY) {
819 820
		if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
			return -EINVAL;
821
		copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
822 823 824
		if (IS_ERR(copy))
			return PTR_ERR(copy);
	}
825
	mode = convert_mode(&msgtyp, msgflg);
L
Linus Torvalds 已提交
826

827 828
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
829
	if (IS_ERR(msq)) {
830
		rcu_read_unlock();
831
		free_copy(copy);
832
		return PTR_ERR(msq);
833
	}
L
Linus Torvalds 已提交
834 835 836 837 838

	for (;;) {
		struct msg_receiver msr_d;

		msg = ERR_PTR(-EACCES);
839
		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
840
			goto out_unlock1;
L
Linus Torvalds 已提交
841

842
		ipc_lock_object(&msq->q_perm);
843 844

		/* raced with RMID? */
845
		if (!ipc_valid_object(&msq->q_perm)) {
846 847 848 849
			msg = ERR_PTR(-EIDRM);
			goto out_unlock0;
		}

850
		msg = find_msg(msq, &msgtyp, mode);
851 852 853 854 855
		if (!IS_ERR(msg)) {
			/*
			 * Found a suitable message.
			 * Unlink it from the queue.
			 */
856
			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
L
Linus Torvalds 已提交
857
				msg = ERR_PTR(-E2BIG);
858
				goto out_unlock0;
L
Linus Torvalds 已提交
859
			}
860 861 862 863
			/*
			 * If we are copying, then do not unlink message and do
			 * not update queue parameters.
			 */
864 865
			if (msgflg & MSG_COPY) {
				msg = copy_msg(msg, copy);
866
				goto out_unlock0;
867
			}
868

L
Linus Torvalds 已提交
869 870 871
			list_del(&msg->m_list);
			msq->q_qnum--;
			msq->q_rtime = get_seconds();
872
			msq->q_lrpid = task_tgid_vnr(current);
L
Linus Torvalds 已提交
873
			msq->q_cbytes -= msg->m_ts;
874 875
			atomic_sub(msg->m_ts, &ns->msg_bytes);
			atomic_dec(&ns->msg_hdrs);
876
			ss_wakeup(&msq->q_senders, 0);
877 878

			goto out_unlock0;
L
Linus Torvalds 已提交
879
		}
880

L
Linus Torvalds 已提交
881 882 883
		/* No message waiting. Wait for a message */
		if (msgflg & IPC_NOWAIT) {
			msg = ERR_PTR(-ENOMSG);
884
			goto out_unlock0;
L
Linus Torvalds 已提交
885
		}
886

887
		list_add_tail(&msr_d.r_list, &msq->q_receivers);
L
Linus Torvalds 已提交
888 889 890
		msr_d.r_tsk = current;
		msr_d.r_msgtype = msgtyp;
		msr_d.r_mode = mode;
891
		if (msgflg & MSG_NOERROR)
L
Linus Torvalds 已提交
892
			msr_d.r_maxsize = INT_MAX;
893
		else
894
			msr_d.r_maxsize = bufsz;
L
Linus Torvalds 已提交
895
		msr_d.r_msg = ERR_PTR(-EAGAIN);
896
		__set_current_state(TASK_INTERRUPTIBLE);
L
Linus Torvalds 已提交
897

898 899
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
L
Linus Torvalds 已提交
900 901
		schedule();

902 903 904 905 906 907
		/*
		 * Lockless receive, part 1:
		 * We don't hold a reference to the queue and getting a
		 * reference would defeat the idea of a lockless operation,
		 * thus the code relies on rcu to guarantee the existence of
		 * msq:
L
Linus Torvalds 已提交
908 909 910 911 912
		 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
		 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
		 */
		rcu_read_lock();

913 914 915 916 917 918
		/*
		 * Lockless receive, part 2:
		 * The work in pipelined_send() and expunge_all():
		 * - Set pointer to message
		 * - Queue the receiver task for later wakeup
		 * - Wake up the process after the lock is dropped.
919
		 *
920 921
		 * Should the process wake up before this wakeup (due to a
		 * signal) it will either see the message and continue ...
L
Linus Torvalds 已提交
922
		 */
923
		msg = READ_ONCE(msr_d.r_msg);
924 925
		if (msg != ERR_PTR(-EAGAIN))
			goto out_unlock1;
L
Linus Torvalds 已提交
926

927 928 929 930
		 /*
		  * ... or see -EAGAIN, acquire the lock to check the message
		  * again.
		  */
931
		ipc_lock_object(&msq->q_perm);
L
Linus Torvalds 已提交
932

933
		msg = msr_d.r_msg;
934
		if (msg != ERR_PTR(-EAGAIN))
935
			goto out_unlock0;
L
Linus Torvalds 已提交
936 937 938 939

		list_del(&msr_d.r_list);
		if (signal_pending(current)) {
			msg = ERR_PTR(-ERESTARTNOHAND);
940
			goto out_unlock0;
L
Linus Torvalds 已提交
941
		}
942 943

		ipc_unlock_object(&msq->q_perm);
L
Linus Torvalds 已提交
944
	}
945 946 947 948 949

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
out_unlock1:
	rcu_read_unlock();
950
	if (IS_ERR(msg)) {
951
		free_copy(copy);
952
		return PTR_ERR(msg);
953
	}
L
Linus Torvalds 已提交
954

955
	bufsz = msg_handler(buf, msg, bufsz);
L
Linus Torvalds 已提交
956
	free_msg(msg);
957

958
	return bufsz;
L
Linus Torvalds 已提交
959 960
}

961 962
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		long, msgtyp, int, msgflg)
963
{
964
	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
965 966
}

967 968 969 970 971

void msg_init_ns(struct ipc_namespace *ns)
{
	ns->msg_ctlmax = MSGMAX;
	ns->msg_ctlmnb = MSGMNB;
972
	ns->msg_ctlmni = MSGMNI;
973 974 975 976 977 978 979 980 981 982 983 984 985 986

	atomic_set(&ns->msg_bytes, 0);
	atomic_set(&ns->msg_hdrs, 0);
	ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
}

#ifdef CONFIG_IPC_NS
void msg_exit_ns(struct ipc_namespace *ns)
{
	free_ipcs(ns, &msg_ids(ns), freeque);
	idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
}
#endif

L
Linus Torvalds 已提交
987
#ifdef CONFIG_PROC_FS
988
static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
L
Linus Torvalds 已提交
989
{
990
	struct user_namespace *user_ns = seq_user_ns(s);
991 992
	struct msg_queue *msq = it;

993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
	seq_printf(s,
		   "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
		   msq->q_perm.key,
		   msq->q_perm.id,
		   msq->q_perm.mode,
		   msq->q_cbytes,
		   msq->q_qnum,
		   msq->q_lspid,
		   msq->q_lrpid,
		   from_kuid_munged(user_ns, msq->q_perm.uid),
		   from_kgid_munged(user_ns, msq->q_perm.gid),
		   from_kuid_munged(user_ns, msq->q_perm.cuid),
		   from_kgid_munged(user_ns, msq->q_perm.cgid),
		   msq->q_stime,
		   msq->q_rtime,
		   msq->q_ctime);

	return 0;
L
Linus Torvalds 已提交
1011 1012
}
#endif
1013 1014 1015 1016 1017 1018 1019 1020 1021

void __init msg_init(void)
{
	msg_init_ns(&init_ipc_ns);

	ipc_init_proc_interface("sysvipc/msg",
				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
				IPC_MSG_IDS, sysvipc_msg_proc_show);
}