msg.c 23.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;
61
	size_t                  msgsz;
L
Linus Torvalds 已提交
62 63 64 65 66 67
};

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

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

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

	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 已提交
93 94 95 96 97
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
{
	ipc_rmid(&msg_ids(ns), &s->q_perm);
}

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

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

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

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

	msq->q_stime = msq->q_rtime = 0;
	msq->q_ctime = get_seconds();
	msq->q_cbytes = msq->q_qnum = 0;
K
Kirill Korotaev 已提交
138
	msq->q_qbytes = ns->msg_ctlmnb;
L
Linus Torvalds 已提交
139 140 141 142
	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 已提交
143

144 145 146 147 148 149 150
	/* 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;
	}

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

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

157 158 159 160 161 162 163 164
static inline bool msg_fits_inqueue(struct msg_queue *msq, size_t msgsz)
{
	return msgsz + msq->q_cbytes <= msq->q_qbytes &&
		1 + msq->q_qnum <= msq->q_qbytes;
}

static inline void ss_add(struct msg_queue *msq,
			  struct msg_sender *mss, size_t msgsz)
L
Linus Torvalds 已提交
165
{
166
	mss->tsk = current;
167
	mss->msgsz = msgsz;
168
	__set_current_state(TASK_INTERRUPTIBLE);
169
	list_add_tail(&mss->list, &msq->q_senders);
L
Linus Torvalds 已提交
170 171
}

172
static inline void ss_del(struct msg_sender *mss)
L
Linus Torvalds 已提交
173
{
174
	if (mss->list.next)
L
Linus Torvalds 已提交
175 176 177
		list_del(&mss->list);
}

178
static void ss_wakeup(struct msg_queue *msq,
179
		      struct wake_q_head *wake_q, bool kill)
L
Linus Torvalds 已提交
180
{
181
	struct msg_sender *mss, *t;
182 183
	struct task_struct *stop_tsk = NULL;
	struct list_head *h = &msq->q_senders;
L
Linus Torvalds 已提交
184

185
	list_for_each_entry_safe(mss, t, h, list) {
186 187
		if (kill)
			mss->list.next = NULL;
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

		/*
		 * Stop at the first task we don't wakeup,
		 * we've already iterated the original
		 * sender queue.
		 */
		else if (stop_tsk == mss->tsk)
			break;
		/*
		 * We are not in an EIDRM scenario here, therefore
		 * verify that we really need to wakeup the task.
		 * To maintain current semantics and wakeup order,
		 * move the sender to the tail on behalf of the
		 * blocked task.
		 */
		else if (!msg_fits_inqueue(msq, mss->msgsz)) {
			if (!stop_tsk)
				stop_tsk = mss->tsk;

			list_move_tail(&mss->list, &msq->q_senders);
			continue;
		}

211
		wake_q_add(wake_q, mss->tsk);
L
Linus Torvalds 已提交
212 213 214
	}
}

215 216
static void expunge_all(struct msg_queue *msq, int res,
			struct wake_q_head *wake_q)
L
Linus Torvalds 已提交
217
{
218
	struct msg_receiver *msr, *t;
219

220
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
221 222
		wake_q_add(wake_q, msr->r_tsk);
		WRITE_ONCE(msr->r_msg, ERR_PTR(res));
L
Linus Torvalds 已提交
223 224
	}
}
225 226 227

/*
 * freeque() wakes up waiters on the sender and receiver waiting queue,
N
Nadia Derbey 已提交
228 229
 * removes the message queue from message queue ID IDR, and cleans up all the
 * messages associated with this queue.
L
Linus Torvalds 已提交
230
 *
D
Davidlohr Bueso 已提交
231 232
 * 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 已提交
233
 */
234
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
L
Linus Torvalds 已提交
235
{
236
	struct msg_msg *msg, *t;
237
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
238
	DEFINE_WAKE_Q(wake_q);
L
Linus Torvalds 已提交
239

240
	expunge_all(msq, -EIDRM, &wake_q);
241
	ss_wakeup(msq, &wake_q, true);
N
Nadia Derbey 已提交
242
	msg_rmid(ns, msq);
D
Davidlohr Bueso 已提交
243
	ipc_unlock_object(&msq->q_perm);
244
	wake_up_q(&wake_q);
D
Davidlohr Bueso 已提交
245
	rcu_read_unlock();
246

247
	list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
248
		atomic_dec(&ns->msg_hdrs);
L
Linus Torvalds 已提交
249 250
		free_msg(msg);
	}
251
	atomic_sub(msq->q_cbytes, &ns->msg_bytes);
D
Davidlohr Bueso 已提交
252
	ipc_rcu_putref(msq, msg_rcu_free);
L
Linus Torvalds 已提交
253 254
}

N
Nadia Derbey 已提交
255
/*
D
Davidlohr Bueso 已提交
256
 * Called with msg_ids.rwsem and ipcp locked.
N
Nadia Derbey 已提交
257
 */
N
Nadia Derbey 已提交
258
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
N
Nadia Derbey 已提交
259
{
N
Nadia Derbey 已提交
260 261 262
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);

	return security_msg_queue_associate(msq, msgflg);
N
Nadia Derbey 已提交
263 264
}

265
SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
L
Linus Torvalds 已提交
266
{
K
Kirill Korotaev 已提交
267
	struct ipc_namespace *ns;
M
Mathias Krause 已提交
268 269 270 271
	static const struct ipc_ops msg_ops = {
		.getnew = newque,
		.associate = msg_security,
	};
N
Nadia Derbey 已提交
272
	struct ipc_params msg_params;
K
Kirill Korotaev 已提交
273 274

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

N
Nadia Derbey 已提交
276 277
	msg_params.key = key;
	msg_params.flg = msgflg;
278

N
Nadia Derbey 已提交
279
	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
L
Linus Torvalds 已提交
280 281
}

282 283
static inline unsigned long
copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
L
Linus Torvalds 已提交
284
{
M
Manfred Spraul 已提交
285
	switch (version) {
L
Linus Torvalds 已提交
286
	case IPC_64:
287
		return copy_to_user(buf, in, sizeof(*in));
L
Linus Torvalds 已提交
288
	case IPC_OLD:
289
	{
L
Linus Torvalds 已提交
290 291
		struct msqid_ds out;

292
		memset(&out, 0, sizeof(out));
L
Linus Torvalds 已提交
293 294 295 296 297 298 299

		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;

300 301
		if (in->msg_cbytes > USHRT_MAX)
			out.msg_cbytes	= USHRT_MAX;
L
Linus Torvalds 已提交
302 303 304 305
		else
			out.msg_cbytes	= in->msg_cbytes;
		out.msg_lcbytes		= in->msg_cbytes;

306 307
		if (in->msg_qnum > USHRT_MAX)
			out.msg_qnum	= USHRT_MAX;
L
Linus Torvalds 已提交
308 309 310
		else
			out.msg_qnum	= in->msg_qnum;

311 312
		if (in->msg_qbytes > USHRT_MAX)
			out.msg_qbytes	= USHRT_MAX;
L
Linus Torvalds 已提交
313 314 315 316 317 318 319
		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;

320 321
		return copy_to_user(buf, &out, sizeof(out));
	}
L
Linus Torvalds 已提交
322 323 324 325 326
	default:
		return -EINVAL;
	}
}

327
static inline unsigned long
328
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
L
Linus Torvalds 已提交
329
{
M
Manfred Spraul 已提交
330
	switch (version) {
L
Linus Torvalds 已提交
331
	case IPC_64:
332
		if (copy_from_user(out, buf, sizeof(*out)))
L
Linus Torvalds 已提交
333 334 335
			return -EFAULT;
		return 0;
	case IPC_OLD:
336
	{
L
Linus Torvalds 已提交
337 338
		struct msqid_ds tbuf_old;

339
		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
L
Linus Torvalds 已提交
340 341
			return -EFAULT;

M
Manfred Spraul 已提交
342 343 344
		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 已提交
345

346
		if (tbuf_old.msg_qbytes == 0)
347
			out->msg_qbytes	= tbuf_old.msg_lqbytes;
L
Linus Torvalds 已提交
348
		else
349
			out->msg_qbytes	= tbuf_old.msg_qbytes;
L
Linus Torvalds 已提交
350 351

		return 0;
352
	}
L
Linus Torvalds 已提交
353 354 355 356 357
	default:
		return -EINVAL;
	}
}

358
/*
D
Davidlohr Bueso 已提交
359
 * This function handles some msgctl commands which require the rwsem
360
 * to be held in write mode.
D
Davidlohr Bueso 已提交
361
 * NOTE: no locks must be held, the rwsem is taken inside this function.
362 363 364
 */
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
		       struct msqid_ds __user *buf, int version)
L
Linus Torvalds 已提交
365 366
{
	struct kern_ipc_perm *ipcp;
367
	struct msqid64_ds uninitialized_var(msqid64);
368 369 370 371
	struct msg_queue *msq;
	int err;

	if (cmd == IPC_SET) {
372
		if (copy_msqid_from_user(&msqid64, buf, version))
373 374 375
			return -EFAULT;
	}

D
Davidlohr Bueso 已提交
376
	down_write(&msg_ids(ns).rwsem);
377 378
	rcu_read_lock();

379 380
	ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
				      &msqid64.msg_perm, msqid64.msg_qbytes);
381 382 383 384
	if (IS_ERR(ipcp)) {
		err = PTR_ERR(ipcp);
		goto out_unlock1;
	}
385

386
	msq = container_of(ipcp, struct msg_queue, q_perm);
387 388 389

	err = security_msg_queue_msgctl(msq, cmd);
	if (err)
390
		goto out_unlock1;
391 392 393

	switch (cmd) {
	case IPC_RMID:
394
		ipc_lock_object(&msq->q_perm);
395
		/* freeque unlocks the ipc object and rcu */
396 397 398
		freeque(ns, ipcp);
		goto out_up;
	case IPC_SET:
399
	{
400
		DEFINE_WAKE_Q(wake_q);
401

402
		if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
403 404
		    !capable(CAP_SYS_RESOURCE)) {
			err = -EPERM;
405
			goto out_unlock1;
406 407
		}

408
		ipc_lock_object(&msq->q_perm);
409 410
		err = ipc_update_perm(&msqid64.msg_perm, ipcp);
		if (err)
411
			goto out_unlock0;
412

413
		msq->q_qbytes = msqid64.msg_qbytes;
414 415

		msq->q_ctime = get_seconds();
416 417
		/*
		 * Sleeping receivers might be excluded by
418 419
		 * stricter permissions.
		 */
420
		expunge_all(msq, -EAGAIN, &wake_q);
421 422
		/*
		 * Sleeping senders might be able to send
423 424
		 * due to a larger queue size.
		 */
425
		ss_wakeup(msq, &wake_q, false);
426 427 428 429 430
		ipc_unlock_object(&msq->q_perm);
		wake_up_q(&wake_q);

		goto out_unlock1;
	}
431 432
	default:
		err = -EINVAL;
433
		goto out_unlock1;
434
	}
435 436 437 438 439

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
out_unlock1:
	rcu_read_unlock();
440
out_up:
D
Davidlohr Bueso 已提交
441
	up_write(&msg_ids(ns).rwsem);
442 443 444
	return err;
}

445 446
static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
			 int cmd, int version, void __user *buf)
447
{
448
	int err;
449
	struct msg_queue *msq;
L
Linus Torvalds 已提交
450 451

	switch (cmd) {
452 453 454
	case IPC_INFO:
	case MSG_INFO:
	{
L
Linus Torvalds 已提交
455 456
		struct msginfo msginfo;
		int max_id;
457

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

461 462
		/*
		 * We must not return kernel stack data.
L
Linus Torvalds 已提交
463 464 465 466 467 468 469
		 * due to padding, it's not enough
		 * to set all member fields.
		 */
		err = security_msg_queue_msgctl(NULL, cmd);
		if (err)
			return err;

470
		memset(&msginfo, 0, sizeof(msginfo));
K
Kirill Korotaev 已提交
471 472 473
		msginfo.msgmni = ns->msg_ctlmni;
		msginfo.msgmax = ns->msg_ctlmax;
		msginfo.msgmnb = ns->msg_ctlmnb;
L
Linus Torvalds 已提交
474 475
		msginfo.msgssz = MSGSSZ;
		msginfo.msgseg = MSGSEG;
D
Davidlohr Bueso 已提交
476
		down_read(&msg_ids(ns).rwsem);
L
Linus Torvalds 已提交
477
		if (cmd == MSG_INFO) {
K
Kirill Korotaev 已提交
478
			msginfo.msgpool = msg_ids(ns).in_use;
479 480
			msginfo.msgmap = atomic_read(&ns->msg_hdrs);
			msginfo.msgtql = atomic_read(&ns->msg_bytes);
L
Linus Torvalds 已提交
481 482 483 484 485
		} else {
			msginfo.msgmap = MSGMAP;
			msginfo.msgpool = MSGPOOL;
			msginfo.msgtql = MSGTQL;
		}
N
Nadia Derbey 已提交
486
		max_id = ipc_get_maxid(&msg_ids(ns));
D
Davidlohr Bueso 已提交
487
		up_read(&msg_ids(ns).rwsem);
488
		if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
L
Linus Torvalds 已提交
489
			return -EFAULT;
490
		return (max_id < 0) ? 0 : max_id;
L
Linus Torvalds 已提交
491
	}
492 493

	case MSG_STAT:
L
Linus Torvalds 已提交
494 495 496 497
	case IPC_STAT:
	{
		struct msqid64_ds tbuf;
		int success_return;
498

L
Linus Torvalds 已提交
499 500 501
		if (!buf)
			return -EFAULT;

502 503 504
		memset(&tbuf, 0, sizeof(tbuf));

		rcu_read_lock();
505
		if (cmd == MSG_STAT) {
506 507 508 509 510
			msq = msq_obtain_object(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
N
Nadia Derbey 已提交
511
			success_return = msq->q_perm.id;
L
Linus Torvalds 已提交
512
		} else {
513 514 515 516 517
			msq = msq_obtain_object_check(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
L
Linus Torvalds 已提交
518 519
			success_return = 0;
		}
520

L
Linus Torvalds 已提交
521
		err = -EACCES;
522
		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
L
Linus Torvalds 已提交
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
			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;
538 539
		rcu_read_unlock();

L
Linus Torvalds 已提交
540 541 542 543
		if (copy_msqid_to_user(buf, &tbuf, version))
			return -EFAULT;
		return success_return;
	}
544

L
Linus Torvalds 已提交
545
	default:
546
		return -EINVAL;
L
Linus Torvalds 已提交
547 548
	}

549
	return err;
L
Linus Torvalds 已提交
550
out_unlock:
551
	rcu_read_unlock();
L
Linus Torvalds 已提交
552 553 554
	return err;
}

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
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;
	}
}

580
static int testmsg(struct msg_msg *msg, long type, int mode)
L
Linus Torvalds 已提交
581
{
P
Paul McQuade 已提交
582 583 584 585 586 587 588 589 590 591
	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 已提交
592
			return 1;
P
Paul McQuade 已提交
593 594 595 596 597
		break;
	case SEARCH_NOTEQUAL:
		if (msg->m_type != type)
			return 1;
		break;
L
Linus Torvalds 已提交
598 599 600 601
	}
	return 0;
}

602 603
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
				 struct wake_q_head *wake_q)
L
Linus Torvalds 已提交
604
{
605
	struct msg_receiver *msr, *t;
606

607
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
608 609 610 611
		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 已提交
612
			list_del(&msr->r_list);
613
			if (msr->r_maxsize < msg->m_ts) {
614 615
				wake_q_add(wake_q, msr->r_tsk);
				WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
L
Linus Torvalds 已提交
616
			} else {
617
				msq->q_lrpid = task_pid_vnr(msr->r_tsk);
L
Linus Torvalds 已提交
618
				msq->q_rtime = get_seconds();
619

620 621
				wake_q_add(wake_q, msr->r_tsk);
				WRITE_ONCE(msr->r_msg, msg);
L
Linus Torvalds 已提交
622 623 624 625
				return 1;
			}
		}
	}
D
Davidlohr Bueso 已提交
626

L
Linus Torvalds 已提交
627 628 629
	return 0;
}

630 631
long do_msgsnd(int msqid, long mtype, void __user *mtext,
		size_t msgsz, int msgflg)
L
Linus Torvalds 已提交
632 633 634 635
{
	struct msg_queue *msq;
	struct msg_msg *msg;
	int err;
K
Kirill Korotaev 已提交
636
	struct ipc_namespace *ns;
637
	DEFINE_WAKE_Q(wake_q);
K
Kirill Korotaev 已提交
638 639

	ns = current->nsproxy->ipc_ns;
640

K
Kirill Korotaev 已提交
641
	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
L
Linus Torvalds 已提交
642 643 644 645
		return -EINVAL;
	if (mtype < 1)
		return -EINVAL;

646
	msg = load_msg(mtext, msgsz);
647
	if (IS_ERR(msg))
L
Linus Torvalds 已提交
648 649 650 651 652
		return PTR_ERR(msg);

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

653 654
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
655 656
	if (IS_ERR(msq)) {
		err = PTR_ERR(msq);
657
		goto out_unlock1;
658
	}
L
Linus Torvalds 已提交
659

660 661
	ipc_lock_object(&msq->q_perm);

L
Linus Torvalds 已提交
662 663 664
	for (;;) {
		struct msg_sender s;

665
		err = -EACCES;
666
		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
667
			goto out_unlock0;
L
Linus Torvalds 已提交
668

669
		/* raced with RMID? */
670
		if (!ipc_valid_object(&msq->q_perm)) {
671 672 673 674
			err = -EIDRM;
			goto out_unlock0;
		}

L
Linus Torvalds 已提交
675 676
		err = security_msg_queue_msgsnd(msq, msg, msgflg);
		if (err)
677
			goto out_unlock0;
L
Linus Torvalds 已提交
678

679
		if (msg_fits_inqueue(msq, msgsz))
L
Linus Torvalds 已提交
680 681 682
			break;

		/* queue full, wait: */
683 684
		if (msgflg & IPC_NOWAIT) {
			err = -EAGAIN;
685
			goto out_unlock0;
L
Linus Torvalds 已提交
686
		}
687

D
Davidlohr Bueso 已提交
688
		/* enqueue the sender and prepare to block */
689
		ss_add(msq, &s, msgsz);
690 691 692

		if (!ipc_rcu_getref(msq)) {
			err = -EIDRM;
693
			goto out_unlock0;
694 695
		}

696 697
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
L
Linus Torvalds 已提交
698 699
		schedule();

700 701 702
		rcu_read_lock();
		ipc_lock_object(&msq->q_perm);

703
		ipc_rcu_putref(msq, msg_rcu_free);
704 705
		/* raced with RMID? */
		if (!ipc_valid_object(&msq->q_perm)) {
L
Linus Torvalds 已提交
706
			err = -EIDRM;
707
			goto out_unlock0;
L
Linus Torvalds 已提交
708 709
		}
		ss_del(&s);
710

L
Linus Torvalds 已提交
711
		if (signal_pending(current)) {
712
			err = -ERESTARTNOHAND;
713
			goto out_unlock0;
L
Linus Torvalds 已提交
714
		}
715

L
Linus Torvalds 已提交
716
	}
717

718
	msq->q_lspid = task_tgid_vnr(current);
L
Linus Torvalds 已提交
719 720
	msq->q_stime = get_seconds();

721
	if (!pipelined_send(msq, msg, &wake_q)) {
L
Lucas De Marchi 已提交
722
		/* no one is waiting for this message, enqueue it */
723
		list_add_tail(&msg->m_list, &msq->q_messages);
L
Linus Torvalds 已提交
724 725
		msq->q_cbytes += msgsz;
		msq->q_qnum++;
726 727
		atomic_add(msgsz, &ns->msg_bytes);
		atomic_inc(&ns->msg_hdrs);
L
Linus Torvalds 已提交
728
	}
729

L
Linus Torvalds 已提交
730 731 732
	err = 0;
	msg = NULL;

733 734
out_unlock0:
	ipc_unlock_object(&msq->q_perm);
735
	wake_up_q(&wake_q);
736 737
out_unlock1:
	rcu_read_unlock();
738
	if (msg != NULL)
L
Linus Torvalds 已提交
739 740 741 742
		free_msg(msg);
	return err;
}

743 744
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		int, msgflg)
745 746 747 748 749 750 751 752
{
	long mtype;

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

753
static inline int convert_mode(long *msgtyp, int msgflg)
L
Linus Torvalds 已提交
754
{
755 756
	if (msgflg & MSG_COPY)
		return SEARCH_NUMBER;
757
	/*
L
Linus Torvalds 已提交
758 759 760
	 *  find message of correct type.
	 *  msgtyp = 0 => get first.
	 *  msgtyp > 0 => get first message of matching type.
761
	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).
L
Linus Torvalds 已提交
762
	 */
763
	if (*msgtyp == 0)
L
Linus Torvalds 已提交
764
		return SEARCH_ANY;
765 766
	if (*msgtyp < 0) {
		*msgtyp = -*msgtyp;
L
Linus Torvalds 已提交
767 768
		return SEARCH_LESSEQUAL;
	}
769
	if (msgflg & MSG_EXCEPT)
L
Linus Torvalds 已提交
770 771 772 773
		return SEARCH_NOTEQUAL;
	return SEARCH_EQUAL;
}

774 775 776 777 778 779 780 781 782 783 784 785 786 787
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;
}

788
#ifdef CONFIG_CHECKPOINT_RESTORE
789 790 791 792
/*
 * This function creates new kernel message structure, large enough to store
 * bufsz message bytes.
 */
793
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
794 795 796 797 798 799 800 801 802 803 804 805
{
	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;
}

806
static inline void free_copy(struct msg_msg *copy)
807
{
808
	if (copy)
809 810 811
		free_msg(copy);
}
#else
812
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
813 814 815 816
{
	return ERR_PTR(-ENOSYS);
}

817 818 819
static inline void free_copy(struct msg_msg *copy)
{
}
820 821
#endif

822 823
static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
{
824
	struct msg_msg *msg, *found = NULL;
825 826 827 828 829 830 831 832
	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;
833
				found = msg;
834 835 836 837 838 839 840 841 842
			} else if (mode == SEARCH_NUMBER) {
				if (*msgtyp == count)
					return msg;
			} else
				return msg;
			count++;
		}
	}

843
	return found ?: ERR_PTR(-EAGAIN);
844 845
}

846
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
847
	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
L
Linus Torvalds 已提交
848 849
{
	int mode;
850
	struct msg_queue *msq;
K
Kirill Korotaev 已提交
851
	struct ipc_namespace *ns;
852
	struct msg_msg *msg, *copy = NULL;
853
	DEFINE_WAKE_Q(wake_q);
L
Linus Torvalds 已提交
854

855 856
	ns = current->nsproxy->ipc_ns;

857
	if (msqid < 0 || (long) bufsz < 0)
L
Linus Torvalds 已提交
858
		return -EINVAL;
859

860
	if (msgflg & MSG_COPY) {
861 862
		if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
			return -EINVAL;
863
		copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
864 865 866
		if (IS_ERR(copy))
			return PTR_ERR(copy);
	}
867
	mode = convert_mode(&msgtyp, msgflg);
L
Linus Torvalds 已提交
868

869 870
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
871
	if (IS_ERR(msq)) {
872
		rcu_read_unlock();
873
		free_copy(copy);
874
		return PTR_ERR(msq);
875
	}
L
Linus Torvalds 已提交
876 877 878 879 880

	for (;;) {
		struct msg_receiver msr_d;

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

884
		ipc_lock_object(&msq->q_perm);
885 886

		/* raced with RMID? */
887
		if (!ipc_valid_object(&msq->q_perm)) {
888 889 890 891
			msg = ERR_PTR(-EIDRM);
			goto out_unlock0;
		}

892
		msg = find_msg(msq, &msgtyp, mode);
893 894 895 896 897
		if (!IS_ERR(msg)) {
			/*
			 * Found a suitable message.
			 * Unlink it from the queue.
			 */
898
			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
L
Linus Torvalds 已提交
899
				msg = ERR_PTR(-E2BIG);
900
				goto out_unlock0;
L
Linus Torvalds 已提交
901
			}
902 903 904 905
			/*
			 * If we are copying, then do not unlink message and do
			 * not update queue parameters.
			 */
906 907
			if (msgflg & MSG_COPY) {
				msg = copy_msg(msg, copy);
908
				goto out_unlock0;
909
			}
910

L
Linus Torvalds 已提交
911 912 913
			list_del(&msg->m_list);
			msq->q_qnum--;
			msq->q_rtime = get_seconds();
914
			msq->q_lrpid = task_tgid_vnr(current);
L
Linus Torvalds 已提交
915
			msq->q_cbytes -= msg->m_ts;
916 917
			atomic_sub(msg->m_ts, &ns->msg_bytes);
			atomic_dec(&ns->msg_hdrs);
918
			ss_wakeup(msq, &wake_q, false);
919 920

			goto out_unlock0;
L
Linus Torvalds 已提交
921
		}
922

L
Linus Torvalds 已提交
923 924 925
		/* No message waiting. Wait for a message */
		if (msgflg & IPC_NOWAIT) {
			msg = ERR_PTR(-ENOMSG);
926
			goto out_unlock0;
L
Linus Torvalds 已提交
927
		}
928

929
		list_add_tail(&msr_d.r_list, &msq->q_receivers);
L
Linus Torvalds 已提交
930 931 932
		msr_d.r_tsk = current;
		msr_d.r_msgtype = msgtyp;
		msr_d.r_mode = mode;
933
		if (msgflg & MSG_NOERROR)
L
Linus Torvalds 已提交
934
			msr_d.r_maxsize = INT_MAX;
935
		else
936
			msr_d.r_maxsize = bufsz;
L
Linus Torvalds 已提交
937
		msr_d.r_msg = ERR_PTR(-EAGAIN);
938
		__set_current_state(TASK_INTERRUPTIBLE);
L
Linus Torvalds 已提交
939

940 941
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
L
Linus Torvalds 已提交
942 943
		schedule();

944 945 946 947 948 949
		/*
		 * 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 已提交
950 951 952 953 954
		 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
		 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
		 */
		rcu_read_lock();

955 956 957 958 959 960
		/*
		 * 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.
961
		 *
962 963
		 * Should the process wake up before this wakeup (due to a
		 * signal) it will either see the message and continue ...
L
Linus Torvalds 已提交
964
		 */
965
		msg = READ_ONCE(msr_d.r_msg);
966 967
		if (msg != ERR_PTR(-EAGAIN))
			goto out_unlock1;
L
Linus Torvalds 已提交
968

969 970 971 972
		 /*
		  * ... or see -EAGAIN, acquire the lock to check the message
		  * again.
		  */
973
		ipc_lock_object(&msq->q_perm);
L
Linus Torvalds 已提交
974

975
		msg = msr_d.r_msg;
976
		if (msg != ERR_PTR(-EAGAIN))
977
			goto out_unlock0;
L
Linus Torvalds 已提交
978 979 980 981

		list_del(&msr_d.r_list);
		if (signal_pending(current)) {
			msg = ERR_PTR(-ERESTARTNOHAND);
982
			goto out_unlock0;
L
Linus Torvalds 已提交
983
		}
984 985

		ipc_unlock_object(&msq->q_perm);
L
Linus Torvalds 已提交
986
	}
987 988 989

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
990
	wake_up_q(&wake_q);
991 992
out_unlock1:
	rcu_read_unlock();
993
	if (IS_ERR(msg)) {
994
		free_copy(copy);
995
		return PTR_ERR(msg);
996
	}
L
Linus Torvalds 已提交
997

998
	bufsz = msg_handler(buf, msg, bufsz);
L
Linus Torvalds 已提交
999
	free_msg(msg);
1000

1001
	return bufsz;
L
Linus Torvalds 已提交
1002 1003
}

1004 1005
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		long, msgtyp, int, msgflg)
1006
{
1007
	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
1008 1009
}

1010 1011 1012 1013 1014

void msg_init_ns(struct ipc_namespace *ns)
{
	ns->msg_ctlmax = MSGMAX;
	ns->msg_ctlmnb = MSGMNB;
1015
	ns->msg_ctlmni = MSGMNI;
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029

	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 已提交
1030
#ifdef CONFIG_PROC_FS
1031
static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
L
Linus Torvalds 已提交
1032
{
1033
	struct user_namespace *user_ns = seq_user_ns(s);
1034 1035
	struct msg_queue *msq = it;

1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	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 已提交
1054 1055
}
#endif
1056 1057 1058 1059 1060 1061 1062 1063 1064

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);
}