msg.c 23.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
/*
 * linux/ipc/msg.c
3
 * Copyright (C) 1992 Krishna Balasubramanian
Linus Torvalds's avatar
Linus Torvalds committed
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>
Steve Grubb's avatar
Steve Grubb committed
16 17 18
 *
 * support for audit of ipc object properties and permission changes
 * Dustin Kirkland <dustin.kirkland@us.ibm.com>
19 20 21 22
 *
 * namespaces support
 * OpenVZ, SWsoft Inc.
 * Pavel Emelianov <xemul@openvz.org>
Linus Torvalds's avatar
Linus Torvalds committed
23 24
 */

25
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28
#include <linux/msg.h>
#include <linux/spinlock.h>
#include <linux/init.h>
29
#include <linux/mm.h>
Linus Torvalds's avatar
Linus Torvalds committed
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>
Nadia Derbey's avatar
Nadia Derbey committed
37
#include <linux/rwsem.h>
38
#include <linux/nsproxy.h>
39
#include <linux/ipc_namespace.h>
Ingo Molnar's avatar
Ingo Molnar committed
40

Linus Torvalds's avatar
Linus Torvalds committed
41
#include <asm/current.h>
42
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
43 44
#include "util.h"

45
/* one msg_receiver structure for each sleeping receiver */
Linus Torvalds's avatar
Linus Torvalds committed
46
struct msg_receiver {
47 48
	struct list_head	r_list;
	struct task_struct	*r_tsk;
Linus Torvalds's avatar
Linus Torvalds committed
49

50 51 52
	int			r_mode;
	long			r_msgtype;
	long			r_maxsize;
Linus Torvalds's avatar
Linus Torvalds committed
53

54 55 56 57 58 59
	/*
	 * Mark r_msg volatile so that the compiler
	 * does not try to get smart and optimize
	 * it. We rely on this for the lockless
	 * receive algorithm.
	 */
60
	struct msg_msg		*volatile r_msg;
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64
};

/* one msg_sender for each sleeping sender */
struct msg_sender {
65 66
	struct list_head	list;
	struct task_struct	*tsk;
Linus Torvalds's avatar
Linus Torvalds committed
67 68 69 70 71 72
};

#define SEARCH_ANY		1
#define SEARCH_EQUAL		2
#define SEARCH_NOTEQUAL		3
#define SEARCH_LESSEQUAL	4
73
#define SEARCH_NUMBER		5
Linus Torvalds's avatar
Linus Torvalds committed
74

75
#define msg_ids(ns)	((ns)->ids[IPC_MSG_IDS])
Linus Torvalds's avatar
Linus Torvalds committed
76

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id)
{
	struct kern_ipc_perm *ipcp = ipc_obtain_object(&msg_ids(ns), id);

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

Nadia Derbey's avatar
Nadia Derbey committed
98 99 100 101 102
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
{
	ipc_rmid(&msg_ids(ns), &s->q_perm);
}

Davidlohr Bueso's avatar
Davidlohr Bueso committed
103 104 105 106 107 108 109 110 111
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);
}

Nadia Derbey's avatar
Nadia Derbey committed
112 113 114 115 116
/**
 * newque - Create a new msg queue
 * @ns: namespace
 * @params: ptr to the structure that contains the key and msgflg
 *
Davidlohr Bueso's avatar
Davidlohr Bueso committed
117
 * Called with msg_ids.rwsem held (writer)
Nadia Derbey's avatar
Nadia Derbey committed
118
 */
Nadia Derbey's avatar
Nadia Derbey committed
119
static int newque(struct ipc_namespace *ns, struct ipc_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
120 121
{
	struct msg_queue *msq;
122
	int id, retval;
Nadia Derbey's avatar
Nadia Derbey committed
123 124
	key_t key = params->key;
	int msgflg = params->flg;
Linus Torvalds's avatar
Linus Torvalds committed
125

126 127
	msq = ipc_rcu_alloc(sizeof(*msq));
	if (!msq)
Linus Torvalds's avatar
Linus Torvalds committed
128 129
		return -ENOMEM;

130
	msq->q_perm.mode = msgflg & S_IRWXUGO;
Linus Torvalds's avatar
Linus Torvalds committed
131 132 133 134 135
	msq->q_perm.key = key;

	msq->q_perm.security = NULL;
	retval = security_msg_queue_alloc(msq);
	if (retval) {
Davidlohr Bueso's avatar
Davidlohr Bueso committed
136
		ipc_rcu_putref(msq, ipc_rcu_free);
Linus Torvalds's avatar
Linus Torvalds committed
137 138 139
		return retval;
	}

140
	/* ipc_addid() locks msq upon success. */
141
	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
142
	if (id < 0) {
Davidlohr Bueso's avatar
Davidlohr Bueso committed
143
		ipc_rcu_putref(msq, msg_rcu_free);
144
		return id;
Linus Torvalds's avatar
Linus Torvalds committed
145 146 147 148 149
	}

	msq->q_stime = msq->q_rtime = 0;
	msq->q_ctime = get_seconds();
	msq->q_cbytes = msq->q_qnum = 0;
150
	msq->q_qbytes = ns->msg_ctlmnb;
Linus Torvalds's avatar
Linus Torvalds committed
151 152 153 154
	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);
Nadia Derbey's avatar
Nadia Derbey committed
155

156
	ipc_unlock_object(&msq->q_perm);
157
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
158

Nadia Derbey's avatar
Nadia Derbey committed
159
	return msq->q_perm.id;
Linus Torvalds's avatar
Linus Torvalds committed
160 161
}

162
static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
Linus Torvalds's avatar
Linus Torvalds committed
163
{
164
	mss->tsk = current;
165
	__set_current_state(TASK_INTERRUPTIBLE);
166
	list_add_tail(&mss->list, &msq->q_senders);
Linus Torvalds's avatar
Linus Torvalds committed
167 168
}

169
static inline void ss_del(struct msg_sender *mss)
Linus Torvalds's avatar
Linus Torvalds committed
170
{
171
	if (mss->list.next != NULL)
Linus Torvalds's avatar
Linus Torvalds committed
172 173 174
		list_del(&mss->list);
}

175
static void ss_wakeup(struct list_head *h, int kill)
Linus Torvalds's avatar
Linus Torvalds committed
176
{
177
	struct msg_sender *mss, *t;
Linus Torvalds's avatar
Linus Torvalds committed
178

179
	list_for_each_entry_safe(mss, t, h, list) {
180 181
		if (kill)
			mss->list.next = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
182 183 184 185
		wake_up_process(mss->tsk);
	}
}

186
static void expunge_all(struct msg_queue *msq, int res)
Linus Torvalds's avatar
Linus Torvalds committed
187
{
188
	struct msg_receiver *msr, *t;
189

190
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
Davidlohr Bueso's avatar
Davidlohr Bueso committed
191
		msr->r_msg = NULL; /* initialize expunge ordering */
Linus Torvalds's avatar
Linus Torvalds committed
192
		wake_up_process(msr->r_tsk);
Davidlohr Bueso's avatar
Davidlohr Bueso committed
193 194 195 196 197 198
		/*
		 * Ensure that the wakeup is visible before setting r_msg as
		 * the receiving end depends on it: either spinning on a nil,
		 * or dealing with -EAGAIN cases. See lockless receive part 1
		 * and 2 in do_msgrcv().
		 */
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201 202
		smp_mb();
		msr->r_msg = ERR_PTR(res);
	}
}
203 204 205

/*
 * freeque() wakes up waiters on the sender and receiver waiting queue,
Nadia Derbey's avatar
Nadia Derbey committed
206 207
 * removes the message queue from message queue ID IDR, and cleans up all the
 * messages associated with this queue.
Linus Torvalds's avatar
Linus Torvalds committed
208
 *
Davidlohr Bueso's avatar
Davidlohr Bueso committed
209 210
 * msg_ids.rwsem (writer) and the spinlock for this message queue are held
 * before freeque() is called. msg_ids.rwsem remains locked on exit.
Linus Torvalds's avatar
Linus Torvalds committed
211
 */
212
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
Linus Torvalds's avatar
Linus Torvalds committed
213
{
214
	struct msg_msg *msg, *t;
215
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
Linus Torvalds's avatar
Linus Torvalds committed
216

217 218
	expunge_all(msq, -EIDRM);
	ss_wakeup(&msq->q_senders, 1);
Nadia Derbey's avatar
Nadia Derbey committed
219
	msg_rmid(ns, msq);
Davidlohr Bueso's avatar
Davidlohr Bueso committed
220 221
	ipc_unlock_object(&msq->q_perm);
	rcu_read_unlock();
222

223
	list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
224
		atomic_dec(&ns->msg_hdrs);
Linus Torvalds's avatar
Linus Torvalds committed
225 226
		free_msg(msg);
	}
227
	atomic_sub(msq->q_cbytes, &ns->msg_bytes);
Davidlohr Bueso's avatar
Davidlohr Bueso committed
228
	ipc_rcu_putref(msq, msg_rcu_free);
Linus Torvalds's avatar
Linus Torvalds committed
229 230
}

Nadia Derbey's avatar
Nadia Derbey committed
231
/*
Davidlohr Bueso's avatar
Davidlohr Bueso committed
232
 * Called with msg_ids.rwsem and ipcp locked.
Nadia Derbey's avatar
Nadia Derbey committed
233
 */
Nadia Derbey's avatar
Nadia Derbey committed
234
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
Nadia Derbey's avatar
Nadia Derbey committed
235
{
Nadia Derbey's avatar
Nadia Derbey committed
236 237 238
	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);

	return security_msg_queue_associate(msq, msgflg);
Nadia Derbey's avatar
Nadia Derbey committed
239 240
}

241
SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
Linus Torvalds's avatar
Linus Torvalds committed
242
{
243
	struct ipc_namespace *ns;
Mathias Krause's avatar
Mathias Krause committed
244 245 246 247
	static const struct ipc_ops msg_ops = {
		.getnew = newque,
		.associate = msg_security,
	};
Nadia Derbey's avatar
Nadia Derbey committed
248
	struct ipc_params msg_params;
249 250

	ns = current->nsproxy->ipc_ns;
Nadia Derbey's avatar
Nadia Derbey committed
251

Nadia Derbey's avatar
Nadia Derbey committed
252 253
	msg_params.key = key;
	msg_params.flg = msgflg;
254

Nadia Derbey's avatar
Nadia Derbey committed
255
	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
Linus Torvalds's avatar
Linus Torvalds committed
256 257
}

258 259
static inline unsigned long
copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
Linus Torvalds's avatar
Linus Torvalds committed
260
{
Manfred Spraul's avatar
Manfred Spraul committed
261
	switch (version) {
Linus Torvalds's avatar
Linus Torvalds committed
262
	case IPC_64:
263
		return copy_to_user(buf, in, sizeof(*in));
Linus Torvalds's avatar
Linus Torvalds committed
264
	case IPC_OLD:
265
	{
Linus Torvalds's avatar
Linus Torvalds committed
266 267
		struct msqid_ds out;

268
		memset(&out, 0, sizeof(out));
Linus Torvalds's avatar
Linus Torvalds committed
269 270 271 272 273 274 275

		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;

276 277
		if (in->msg_cbytes > USHRT_MAX)
			out.msg_cbytes	= USHRT_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
278 279 280 281
		else
			out.msg_cbytes	= in->msg_cbytes;
		out.msg_lcbytes		= in->msg_cbytes;

282 283
		if (in->msg_qnum > USHRT_MAX)
			out.msg_qnum	= USHRT_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
284 285 286
		else
			out.msg_qnum	= in->msg_qnum;

287 288
		if (in->msg_qbytes > USHRT_MAX)
			out.msg_qbytes	= USHRT_MAX;
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291 292 293 294 295
		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;

296 297
		return copy_to_user(buf, &out, sizeof(out));
	}
Linus Torvalds's avatar
Linus Torvalds committed
298 299 300 301 302
	default:
		return -EINVAL;
	}
}

303
static inline unsigned long
304
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
Linus Torvalds's avatar
Linus Torvalds committed
305
{
Manfred Spraul's avatar
Manfred Spraul committed
306
	switch (version) {
Linus Torvalds's avatar
Linus Torvalds committed
307
	case IPC_64:
308
		if (copy_from_user(out, buf, sizeof(*out)))
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311
			return -EFAULT;
		return 0;
	case IPC_OLD:
312
	{
Linus Torvalds's avatar
Linus Torvalds committed
313 314
		struct msqid_ds tbuf_old;

315
		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
Linus Torvalds's avatar
Linus Torvalds committed
316 317
			return -EFAULT;

Manfred Spraul's avatar
Manfred Spraul committed
318 319 320
		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;
Linus Torvalds's avatar
Linus Torvalds committed
321

322
		if (tbuf_old.msg_qbytes == 0)
323
			out->msg_qbytes	= tbuf_old.msg_lqbytes;
Linus Torvalds's avatar
Linus Torvalds committed
324
		else
325
			out->msg_qbytes	= tbuf_old.msg_qbytes;
Linus Torvalds's avatar
Linus Torvalds committed
326 327

		return 0;
328
	}
Linus Torvalds's avatar
Linus Torvalds committed
329 330 331 332 333
	default:
		return -EINVAL;
	}
}

334
/*
Davidlohr Bueso's avatar
Davidlohr Bueso committed
335
 * This function handles some msgctl commands which require the rwsem
336
 * to be held in write mode.
Davidlohr Bueso's avatar
Davidlohr Bueso committed
337
 * NOTE: no locks must be held, the rwsem is taken inside this function.
338 339 340
 */
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
		       struct msqid_ds __user *buf, int version)
Linus Torvalds's avatar
Linus Torvalds committed
341 342
{
	struct kern_ipc_perm *ipcp;
343
	struct msqid64_ds uninitialized_var(msqid64);
344 345 346 347
	struct msg_queue *msq;
	int err;

	if (cmd == IPC_SET) {
348
		if (copy_msqid_from_user(&msqid64, buf, version))
349 350 351
			return -EFAULT;
	}

Davidlohr Bueso's avatar
Davidlohr Bueso committed
352
	down_write(&msg_ids(ns).rwsem);
353 354
	rcu_read_lock();

355 356
	ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
				      &msqid64.msg_perm, msqid64.msg_qbytes);
357 358 359 360
	if (IS_ERR(ipcp)) {
		err = PTR_ERR(ipcp);
		goto out_unlock1;
	}
361

362
	msq = container_of(ipcp, struct msg_queue, q_perm);
363 364 365

	err = security_msg_queue_msgctl(msq, cmd);
	if (err)
366
		goto out_unlock1;
367 368 369

	switch (cmd) {
	case IPC_RMID:
370
		ipc_lock_object(&msq->q_perm);
371
		/* freeque unlocks the ipc object and rcu */
372 373 374
		freeque(ns, ipcp);
		goto out_up;
	case IPC_SET:
375
		if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
376 377
		    !capable(CAP_SYS_RESOURCE)) {
			err = -EPERM;
378
			goto out_unlock1;
379 380
		}

381
		ipc_lock_object(&msq->q_perm);
382 383
		err = ipc_update_perm(&msqid64.msg_perm, ipcp);
		if (err)
384
			goto out_unlock0;
385

386
		msq->q_qbytes = msqid64.msg_qbytes;
387 388 389 390 391 392 393 394 395 396 397 398 399

		msq->q_ctime = get_seconds();
		/* sleeping receivers might be excluded by
		 * stricter permissions.
		 */
		expunge_all(msq, -EAGAIN);
		/* sleeping senders might be able to send
		 * due to a larger queue size.
		 */
		ss_wakeup(&msq->q_senders, 0);
		break;
	default:
		err = -EINVAL;
400
		goto out_unlock1;
401
	}
402 403 404 405 406

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
out_unlock1:
	rcu_read_unlock();
407
out_up:
Davidlohr Bueso's avatar
Davidlohr Bueso committed
408
	up_write(&msg_ids(ns).rwsem);
409 410 411
	return err;
}

412 413
static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
			 int cmd, int version, void __user *buf)
414
{
415
	int err;
416
	struct msg_queue *msq;
Linus Torvalds's avatar
Linus Torvalds committed
417 418

	switch (cmd) {
419 420 421
	case IPC_INFO:
	case MSG_INFO:
	{
Linus Torvalds's avatar
Linus Torvalds committed
422 423
		struct msginfo msginfo;
		int max_id;
424

Linus Torvalds's avatar
Linus Torvalds committed
425 426
		if (!buf)
			return -EFAULT;
427

428 429
		/*
		 * We must not return kernel stack data.
Linus Torvalds's avatar
Linus Torvalds committed
430 431 432 433 434 435 436
		 * due to padding, it's not enough
		 * to set all member fields.
		 */
		err = security_msg_queue_msgctl(NULL, cmd);
		if (err)
			return err;

437
		memset(&msginfo, 0, sizeof(msginfo));
438 439 440
		msginfo.msgmni = ns->msg_ctlmni;
		msginfo.msgmax = ns->msg_ctlmax;
		msginfo.msgmnb = ns->msg_ctlmnb;
Linus Torvalds's avatar
Linus Torvalds committed
441 442
		msginfo.msgssz = MSGSSZ;
		msginfo.msgseg = MSGSEG;
Davidlohr Bueso's avatar
Davidlohr Bueso committed
443
		down_read(&msg_ids(ns).rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
444
		if (cmd == MSG_INFO) {
445
			msginfo.msgpool = msg_ids(ns).in_use;
446 447
			msginfo.msgmap = atomic_read(&ns->msg_hdrs);
			msginfo.msgtql = atomic_read(&ns->msg_bytes);
Linus Torvalds's avatar
Linus Torvalds committed
448 449 450 451 452
		} else {
			msginfo.msgmap = MSGMAP;
			msginfo.msgpool = MSGPOOL;
			msginfo.msgtql = MSGTQL;
		}
Nadia Derbey's avatar
Nadia Derbey committed
453
		max_id = ipc_get_maxid(&msg_ids(ns));
Davidlohr Bueso's avatar
Davidlohr Bueso committed
454
		up_read(&msg_ids(ns).rwsem);
455
		if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
Linus Torvalds's avatar
Linus Torvalds committed
456
			return -EFAULT;
457
		return (max_id < 0) ? 0 : max_id;
Linus Torvalds's avatar
Linus Torvalds committed
458
	}
459 460

	case MSG_STAT:
Linus Torvalds's avatar
Linus Torvalds committed
461 462 463 464
	case IPC_STAT:
	{
		struct msqid64_ds tbuf;
		int success_return;
465

Linus Torvalds's avatar
Linus Torvalds committed
466 467 468
		if (!buf)
			return -EFAULT;

469 470 471
		memset(&tbuf, 0, sizeof(tbuf));

		rcu_read_lock();
472
		if (cmd == MSG_STAT) {
473 474 475 476 477
			msq = msq_obtain_object(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
Nadia Derbey's avatar
Nadia Derbey committed
478
			success_return = msq->q_perm.id;
Linus Torvalds's avatar
Linus Torvalds committed
479
		} else {
480 481 482 483 484
			msq = msq_obtain_object_check(ns, msqid);
			if (IS_ERR(msq)) {
				err = PTR_ERR(msq);
				goto out_unlock;
			}
Linus Torvalds's avatar
Linus Torvalds committed
485 486
			success_return = 0;
		}
487

Linus Torvalds's avatar
Linus Torvalds committed
488
		err = -EACCES;
489
		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
Linus Torvalds's avatar
Linus Torvalds committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
			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;
505 506
		rcu_read_unlock();

Linus Torvalds's avatar
Linus Torvalds committed
507 508 509 510
		if (copy_msqid_to_user(buf, &tbuf, version))
			return -EFAULT;
		return success_return;
	}
511

Linus Torvalds's avatar
Linus Torvalds committed
512
	default:
513
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
514 515
	}

516
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
517
out_unlock:
518
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
519 520 521
	return err;
}

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
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;
	}
}

547
static int testmsg(struct msg_msg *msg, long type, int mode)
Linus Torvalds's avatar
Linus Torvalds committed
548
{
Paul McQuade's avatar
Paul McQuade committed
549 550 551 552 553 554 555 556 557 558
	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)
Linus Torvalds's avatar
Linus Torvalds committed
559
			return 1;
Paul McQuade's avatar
Paul McQuade committed
560 561 562 563 564
		break;
	case SEARCH_NOTEQUAL:
		if (msg->m_type != type)
			return 1;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
565 566 567 568
	}
	return 0;
}

569
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
Linus Torvalds's avatar
Linus Torvalds committed
570
{
571
	struct msg_receiver *msr, *t;
572

573
	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
574 575 576 577
		if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
		    !security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
					       msr->r_msgtype, msr->r_mode)) {

Linus Torvalds's avatar
Linus Torvalds committed
578
			list_del(&msr->r_list);
579
			if (msr->r_maxsize < msg->m_ts) {
Davidlohr Bueso's avatar
Davidlohr Bueso committed
580
				/* initialize pipelined send ordering */
Linus Torvalds's avatar
Linus Torvalds committed
581 582
				msr->r_msg = NULL;
				wake_up_process(msr->r_tsk);
Davidlohr Bueso's avatar
Davidlohr Bueso committed
583
				smp_mb(); /* see barrier comment below */
Linus Torvalds's avatar
Linus Torvalds committed
584 585 586
				msr->r_msg = ERR_PTR(-E2BIG);
			} else {
				msr->r_msg = NULL;
587
				msq->q_lrpid = task_pid_vnr(msr->r_tsk);
Linus Torvalds's avatar
Linus Torvalds committed
588 589
				msq->q_rtime = get_seconds();
				wake_up_process(msr->r_tsk);
Davidlohr Bueso's avatar
Davidlohr Bueso committed
590 591 592 593 594 595
				/*
				 * Ensure that the wakeup is visible before
				 * setting r_msg, as the receiving end depends
				 * on it. See lockless receive part 1 and 2 in
				 * do_msgrcv().
				 */
Linus Torvalds's avatar
Linus Torvalds committed
596 597
				smp_mb();
				msr->r_msg = msg;
598

Linus Torvalds's avatar
Linus Torvalds committed
599 600 601 602
				return 1;
			}
		}
	}
Davidlohr Bueso's avatar
Davidlohr Bueso committed
603

Linus Torvalds's avatar
Linus Torvalds committed
604 605 606
	return 0;
}

607 608
long do_msgsnd(int msqid, long mtype, void __user *mtext,
		size_t msgsz, int msgflg)
Linus Torvalds's avatar
Linus Torvalds committed
609 610 611 612
{
	struct msg_queue *msq;
	struct msg_msg *msg;
	int err;
613 614 615
	struct ipc_namespace *ns;

	ns = current->nsproxy->ipc_ns;
616

617
	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
Linus Torvalds's avatar
Linus Torvalds committed
618 619 620 621
		return -EINVAL;
	if (mtype < 1)
		return -EINVAL;

622
	msg = load_msg(mtext, msgsz);
623
	if (IS_ERR(msg))
Linus Torvalds's avatar
Linus Torvalds committed
624 625 626 627 628
		return PTR_ERR(msg);

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

629 630
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
631 632
	if (IS_ERR(msq)) {
		err = PTR_ERR(msq);
633
		goto out_unlock1;
634
	}
Linus Torvalds's avatar
Linus Torvalds committed
635

636 637
	ipc_lock_object(&msq->q_perm);

Linus Torvalds's avatar
Linus Torvalds committed
638 639 640
	for (;;) {
		struct msg_sender s;

641
		err = -EACCES;
642
		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
643
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
644

645
		/* raced with RMID? */
646
		if (!ipc_valid_object(&msq->q_perm)) {
647 648 649 650
			err = -EIDRM;
			goto out_unlock0;
		}

Linus Torvalds's avatar
Linus Torvalds committed
651 652
		err = security_msg_queue_msgsnd(msq, msg, msgflg);
		if (err)
653
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
654

655
		if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
Linus Torvalds's avatar
Linus Torvalds committed
656 657 658 659 660
				1 + msq->q_qnum <= msq->q_qbytes) {
			break;
		}

		/* queue full, wait: */
661 662
		if (msgflg & IPC_NOWAIT) {
			err = -EAGAIN;
663
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
664
		}
665

Davidlohr Bueso's avatar
Davidlohr Bueso committed
666
		/* enqueue the sender and prepare to block */
Linus Torvalds's avatar
Linus Torvalds committed
667
		ss_add(msq, &s);
668 669 670

		if (!ipc_rcu_getref(msq)) {
			err = -EIDRM;
671
			goto out_unlock0;
672 673
		}

674 675
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
676 677
		schedule();

678 679 680
		rcu_read_lock();
		ipc_lock_object(&msq->q_perm);

Davidlohr Bueso's avatar
Davidlohr Bueso committed
681
		ipc_rcu_putref(msq, ipc_rcu_free);
682 683
		/* raced with RMID? */
		if (!ipc_valid_object(&msq->q_perm)) {
Linus Torvalds's avatar
Linus Torvalds committed
684
			err = -EIDRM;
685
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
686
		}
687

Linus Torvalds's avatar
Linus Torvalds committed
688
		ss_del(&s);
689

Linus Torvalds's avatar
Linus Torvalds committed
690
		if (signal_pending(current)) {
691
			err = -ERESTARTNOHAND;
692
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
693
		}
694

Linus Torvalds's avatar
Linus Torvalds committed
695
	}
696
	msq->q_lspid = task_tgid_vnr(current);
Linus Torvalds's avatar
Linus Torvalds committed
697 698
	msq->q_stime = get_seconds();

699
	if (!pipelined_send(msq, msg)) {
Lucas De Marchi's avatar
Lucas De Marchi committed
700
		/* no one is waiting for this message, enqueue it */
701
		list_add_tail(&msg->m_list, &msq->q_messages);
Linus Torvalds's avatar
Linus Torvalds committed
702 703
		msq->q_cbytes += msgsz;
		msq->q_qnum++;
704 705
		atomic_add(msgsz, &ns->msg_bytes);
		atomic_inc(&ns->msg_hdrs);
Linus Torvalds's avatar
Linus Torvalds committed
706
	}
707

Linus Torvalds's avatar
Linus Torvalds committed
708 709 710
	err = 0;
	msg = NULL;

711 712 713 714
out_unlock0:
	ipc_unlock_object(&msq->q_perm);
out_unlock1:
	rcu_read_unlock();
715
	if (msg != NULL)
Linus Torvalds's avatar
Linus Torvalds committed
716 717 718 719
		free_msg(msg);
	return err;
}

720 721
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		int, msgflg)
722 723 724 725 726 727 728 729
{
	long mtype;

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

730
static inline int convert_mode(long *msgtyp, int msgflg)
Linus Torvalds's avatar
Linus Torvalds committed
731
{
732 733
	if (msgflg & MSG_COPY)
		return SEARCH_NUMBER;
734
	/*
Linus Torvalds's avatar
Linus Torvalds committed
735 736 737
	 *  find message of correct type.
	 *  msgtyp = 0 => get first.
	 *  msgtyp > 0 => get first message of matching type.
738
	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).
Linus Torvalds's avatar
Linus Torvalds committed
739
	 */
740
	if (*msgtyp == 0)
Linus Torvalds's avatar
Linus Torvalds committed
741
		return SEARCH_ANY;
742 743
	if (*msgtyp < 0) {
		*msgtyp = -*msgtyp;
Linus Torvalds's avatar
Linus Torvalds committed
744 745
		return SEARCH_LESSEQUAL;
	}
746
	if (msgflg & MSG_EXCEPT)
Linus Torvalds's avatar
Linus Torvalds committed
747 748 749 750
		return SEARCH_NOTEQUAL;
	return SEARCH_EQUAL;
}

751 752 753 754 755 756 757 758 759 760 761 762 763 764
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;
}

765
#ifdef CONFIG_CHECKPOINT_RESTORE
766 767 768 769
/*
 * This function creates new kernel message structure, large enough to store
 * bufsz message bytes.
 */
770
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
771 772 773 774 775 776 777 778 779 780 781 782
{
	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;
}

783
static inline void free_copy(struct msg_msg *copy)
784
{
785
	if (copy)
786 787 788
		free_msg(copy);
}
#else
789
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
790 791 792 793
{
	return ERR_PTR(-ENOSYS);
}

794 795 796
static inline void free_copy(struct msg_msg *copy)
{
}
797 798
#endif

799 800
static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
{
801
	struct msg_msg *msg, *found = NULL;
802 803 804 805 806 807 808 809
	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;
810
				found = msg;
811 812 813 814 815 816 817 818 819
			} else if (mode == SEARCH_NUMBER) {
				if (*msgtyp == count)
					return msg;
			} else
				return msg;
			count++;
		}
	}

820
	return found ?: ERR_PTR(-EAGAIN);
821 822
}

823
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
824
	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
Linus Torvalds's avatar
Linus Torvalds committed
825 826
{
	int mode;
827
	struct msg_queue *msq;
828
	struct ipc_namespace *ns;
829
	struct msg_msg *msg, *copy = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
830

831 832
	ns = current->nsproxy->ipc_ns;

833
	if (msqid < 0 || (long) bufsz < 0)
Linus Torvalds's avatar
Linus Torvalds committed
834
		return -EINVAL;
835

836
	if (msgflg & MSG_COPY) {
837 838
		if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
			return -EINVAL;
839
		copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
840 841 842
		if (IS_ERR(copy))
			return PTR_ERR(copy);
	}
843
	mode = convert_mode(&msgtyp, msgflg);
Linus Torvalds's avatar
Linus Torvalds committed
844

845 846
	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
847
	if (IS_ERR(msq)) {
848
		rcu_read_unlock();
849
		free_copy(copy);
850
		return PTR_ERR(msq);
851
	}
Linus Torvalds's avatar
Linus Torvalds committed
852 853 854 855 856

	for (;;) {
		struct msg_receiver msr_d;

		msg = ERR_PTR(-EACCES);
857
		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
858
			goto out_unlock1;
Linus Torvalds's avatar
Linus Torvalds committed
859

860
		ipc_lock_object(&msq->q_perm);
861 862

		/* raced with RMID? */
863
		if (!ipc_valid_object(&msq->q_perm)) {
864 865 866 867
			msg = ERR_PTR(-EIDRM);
			goto out_unlock0;
		}

868
		msg = find_msg(msq, &msgtyp, mode);
869 870 871 872 873
		if (!IS_ERR(msg)) {
			/*
			 * Found a suitable message.
			 * Unlink it from the queue.
			 */
874
			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
Linus Torvalds's avatar
Linus Torvalds committed
875
				msg = ERR_PTR(-E2BIG);
876
				goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
877
			}
878 879 880 881
			/*
			 * If we are copying, then do not unlink message and do
			 * not update queue parameters.
			 */
882 883
			if (msgflg & MSG_COPY) {
				msg = copy_msg(msg, copy);
884
				goto out_unlock0;
885
			}
886

Linus Torvalds's avatar
Linus Torvalds committed
887 888 889
			list_del(&msg->m_list);
			msq->q_qnum--;
			msq->q_rtime = get_seconds();
890
			msq->q_lrpid = task_tgid_vnr(current);
Linus Torvalds's avatar
Linus Torvalds committed
891
			msq->q_cbytes -= msg->m_ts;
892 893
			atomic_sub(msg->m_ts, &ns->msg_bytes);
			atomic_dec(&ns->msg_hdrs);
894
			ss_wakeup(&msq->q_senders, 0);
895 896

			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
897
		}
898

Linus Torvalds's avatar
Linus Torvalds committed
899 900 901
		/* No message waiting. Wait for a message */
		if (msgflg & IPC_NOWAIT) {
			msg = ERR_PTR(-ENOMSG);
902
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
903
		}
904

905
		list_add_tail(&msr_d.r_list, &msq->q_receivers);
Linus Torvalds's avatar
Linus Torvalds committed
906 907 908
		msr_d.r_tsk = current;
		msr_d.r_msgtype = msgtyp;
		msr_d.r_mode = mode;
909
		if (msgflg & MSG_NOERROR)
Linus Torvalds's avatar
Linus Torvalds committed
910
			msr_d.r_maxsize = INT_MAX;
911
		else
912
			msr_d.r_maxsize = bufsz;
Linus Torvalds's avatar
Linus Torvalds committed
913
		msr_d.r_msg = ERR_PTR(-EAGAIN);
914
		__set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds's avatar
Linus Torvalds committed
915

916 917
		ipc_unlock_object(&msq->q_perm);
		rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
918 919 920 921 922 923
		schedule();

		/* Lockless receive, part 1:
		 * Disable preemption.  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
Lucas De Marchi's avatar
Lucas De Marchi committed
924
		 * existence of msq:
Linus Torvalds's avatar
Linus Torvalds committed
925 926 927
		 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
		 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
		 * rcu_read_lock() prevents preemption between reading r_msg
928
		 * and acquiring the q_perm.lock in ipc_lock_object().
Linus Torvalds's avatar
Linus Torvalds committed
929 930 931 932 933 934 935 936
		 */
		rcu_read_lock();

		/* Lockless receive, part 2:
		 * Wait until pipelined_send or expunge_all are outside of
		 * wake_up_process(). There is a race with exit(), see
		 * ipc/mqueue.c for the details.
		 */
Manfred Spraul's avatar
Manfred Spraul committed
937
		msg = (struct msg_msg *)msr_d.r_msg;
Linus Torvalds's avatar
Linus Torvalds committed
938 939
		while (msg == NULL) {
			cpu_relax();
940
			msg = (struct msg_msg *)msr_d.r_msg;
Linus Torvalds's avatar
Linus Torvalds committed
941 942 943 944 945 946
		}

		/* Lockless receive, part 3:
		 * If there is a message or an error then accept it without
		 * locking.
		 */
947 948
		if (msg != ERR_PTR(-EAGAIN))
			goto out_unlock1;
Linus Torvalds's avatar
Linus Torvalds committed
949 950 951 952

		/* Lockless receive, part 3:
		 * Acquire the queue spinlock.
		 */
953
		ipc_lock_object(&msq->q_perm);
Linus Torvalds's avatar
Linus Torvalds committed
954 955 956 957

		/* Lockless receive, part 4:
		 * Repeat test after acquiring the spinlock.
		 */
Manfred Spraul's avatar
Manfred Spraul committed
958
		msg = (struct msg_msg *)msr_d.r_msg;
959
		if (msg != ERR_PTR(-EAGAIN))
960
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
961 962 963 964

		list_del(&msr_d.r_list);
		if (signal_pending(current)) {
			msg = ERR_PTR(-ERESTARTNOHAND);
965
			goto out_unlock0;
Linus Torvalds's avatar
Linus Torvalds committed
966
		}
967 968

		ipc_unlock_object(&msq->q_perm);
Linus Torvalds's avatar
Linus Torvalds committed
969
	}
970 971 972 973 974

out_unlock0:
	ipc_unlock_object(&msq->q_perm);
out_unlock1:
	rcu_read_unlock();
975
	if (IS_ERR(msg)) {
976
		free_copy(copy);
977
		return PTR_ERR(msg);
978
	}
Linus Torvalds's avatar
Linus Torvalds committed
979

980
	bufsz = msg_handler(buf, msg, bufsz);
Linus Torvalds's avatar
Linus Torvalds committed
981
	free_msg(msg);
982

983
	return bufsz;
Linus Torvalds's avatar
Linus Torvalds committed
984 985
}

986 987
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
		long, msgtyp, int, msgflg)
988
{
989
	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
990 991
}

992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
/*
 * Scale msgmni with the available lowmem size: the memory dedicated to msg
 * queues should occupy at most 1/MSG_MEM_SCALE of lowmem.
 * Also take into account the number of nsproxies created so far.
 * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
 */
void recompute_msgmni(struct ipc_namespace *ns)
{
	struct sysinfo i;
	unsigned long allowed;
	int nb_ns;

	si_meminfo(&i);
	allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit)
		/ MSGMNB;
	nb_ns = atomic_read(&nr_ipc_ns);
	allowed /= nb_ns;

	if (allowed < MSGMNI) {
		ns->msg_ctlmni = MSGMNI;
		return;
	}

	if (allowed > IPCMNI / nb_ns) {
		ns->msg_ctlmni = IPCMNI / nb_ns;
		return;
	}

	ns->msg_ctlmni = allowed;
}

void msg_init_ns(struct ipc_namespace *ns)
{
	ns->msg_ctlmax = MSGMAX;
	ns->msg_ctlmnb = MSGMNB;

	recompute_msgmni(ns);

	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

Linus Torvalds's avatar
Linus Torvalds committed
1043
#ifdef CONFIG_PROC_FS
1044
static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
Linus Torvalds's avatar
Linus Torvalds committed
1045
{
1046
	struct user_namespace *user_ns = seq_user_ns(s);
1047 1048 1049
	struct msg_queue *msq = it;

	return seq_printf(s,
1050 1051
			"%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
			msq->q_perm.key,
Nadia Derbey's avatar
Nadia Derbey committed
1052
			msq->q_perm.id,
1053 1054 1055 1056 1057
			msq->q_perm.mode,
			msq->q_cbytes,
			msq->q_qnum,
			msq->q_lspid,
			msq->q_lrpid,
1058 1059 1060 1061
			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),
1062 1063 1064
			msq->q_stime,
			msq->q_rtime,
			msq->q_ctime);
Linus Torvalds's avatar
Linus Torvalds committed
1065 1066
}
#endif
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078

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

	printk(KERN_INFO "msgmni has been set to %d\n",
		init_ipc_ns.msg_ctlmni);

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